/*
 * Copyright (C) 2011-2013 Eric Lasota
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include <string.h>
#include <stdio.h>
#include <new>

#include "rdx_pragmas.hpp"

#include "rdx_programmability.hpp"
#include "rdx_objectmanagement.hpp"
#include "rdx_hashmap.hpp"
#include "rdx_basictypes.hpp"
#include "rdx_opcodes.hpp"
#include "rdx_constants.hpp"

#include "rdx_longflow.hpp"
#include "rdx_io.hpp"
#include "rdx_ilcomp.hpp"
#include "rdx_intrinsics.hpp"
#include "rdx_runtime.hpp"
#include "rdx_lut.hpp"

static const RDX::LargeInt STRING_ENCODE_BACKLOG_SIZE = 50;


namespace RDX
{
	namespace ObjectManagement
	{
		using namespace RDX::Programmability;
		using namespace RDX::Collections;
		using namespace RDX::Utility;

		struct CandidateString
		{
			enum CSFormat
			{
				CSF_ASCII,
				CSF_UTF8,
				CSF_Char,
				CSF_Concatenated,
			};

			CSFormat format;
			const void *bytes;
			LargeInt numBytes;

			const void *bytes2;
			LargeInt numBytes2;

			LargeInt numCharacters;

			Char *feedback;

			// Decodes a single character from a byte stream
			Char DecodeCharacter(const void **pData, LargeInt *pAvailableBytes) const;
			// Returns a count of characters, returns true if the string is valid, false otherwise
			bool CountCharacters();
		};

		// Hash table that maps character arrays to strings
		struct HashMapStringTable : public HashMapSimple<Char*, const String*>
		{
			typedef CandidateString CandidateKey;
			typedef const String *Value;

			typedef HashEntry<Char*, const String*> MyHashEntry;

			// Reference to the char[C] type
			const ArrayOfType *_aot_ConstChar;

			void InitializeElement(MyHashEntry *v);
			LargeInt UnitSize() const;
			bool CompareKey(const CandidateString *cs, const HashEntry<Char*, const String*> *e) const;
			HashValue HashCKey(const void *ckey) const;

			Char *ConstructKey(OperationContext *ctx, const void *ckey, bool &recheck);
		};

		class RDXObjectManager : public IObjectManager
		{
		public:
			struct StringTableEntry
			{
				Collections::HashElement e;
				Char *k;
				String *v;
			};

			struct GCObjectList
			{
				GCInfo **objects;
				LargeInt numObjects;

				inline void Add(OperationContext *ctx, IObjectManager *objm, GCInfo *obj)
				{
					RDX_TRY(ctx)
					{
						LargeInt capacity = 0;
						if(objects)
							capacity = GCInfo::From(objects)->numElements;

						if(objects == NULL)
							numObjects = 0;		// Shut up analyze

						if(numObjects == capacity)
						{
							// Enlarge
							GCInfo **newObjects;
							if(!CheckMulOverflow(numObjects, 2))
								RDX_STHROW(ctx, Errors::RDX_ERROR_INTEGER_OVERFLOW);

							LargeInt newCapacity = numObjects * 2;
							if(newCapacity == 0)
								newCapacity = 8;
							RDX_PROTECT_ASSIGN(ctx, newObjects, objm->Create1DArray<GCInfo*>(ctx, newCapacity));
							for(LargeInt i=0;i<numObjects;i++)
								newObjects[i] = objects[i];
							objects = newObjects;
						}
						objects[numObjects++] = obj;
					}
					RDX_CATCH(ctx)
					{
						RDX_RETHROW(ctx);
					}
					RDX_ENDTRY
				}

				inline void EvictAll()
				{
					objects = NULL;
					numObjects = 0;
				}
			};

			enum SaveMode
			{
				SAVEMODE_SingleObject,
				SAVEMODE_Package,
			};

		private:
			BuiltIns _builtins;
			Allocator _allocator;
			const INativeTypeHost *_nth;
			const ICodeProvider *_codeProvider;

			PossiblyAtomicInt _stringReadAttempts;
			PossiblyAtomicInt _stringWriteAttempts;
			Collections::HashMap<HashMapStringTable> _stringTable;
			
			static const LargeInt STRING_ENCODE_BACKLOG_SIZE	= 50;

			Collections::HashMap<HashMapSimple<const String*, LoadShell> > _parseLocalResources;
			Collections::HashMap<HashMapSimple<const String*, LoadShell> > _parseImportedResources;
			Collections::HashMap<HashMapSimple<const String*, void*> > _gst;
			Collections::HashMap<HashMapSimple<Domain, Package*> > _packages;

			GCLink _liveSetGCL;
			GCLink _scanSetGCL;
			
			GCObjectList _pendingDeshellObjects;
			GCObjectList _pendingProcessObjects;
			GCObjectList _unloadedPackages;

			GCInfo _linkHead;
			GCInfo _linkTail;
			ScanID _currentScanID;
			LargeInt _scanObjectCounter[GCL_Count];

			bool _initialized;
			
			NonAtomicInt _gcFrequency;
			PossiblyAtomicInt _gcCounter;
			bool _shouldDisposeIL;

			PossiblyAtomicInt _activeThreadCount;
#ifdef RDX_ENABLE_SMP
			volatile bool _operationsActive[COREMUTEX_Count];
			CRef<Threading::IMutex> _coreMutexes[COREMUTEX_Count];
			bool _ignoreMutexesDuringSyncs;
#endif
			bool _forcePackagesRelevant;

			CRef<void> *_crefLinkHead;

			void InitializeAOT(OperationContext *ctx, CRef<ArrayOfType> &aotRef, const char *name, CRef<StructuredType> &subtypeRef);
			void IncludeGCList(ISerializer &gc, GCObjectList *gcol);

		public:
			RDXObjectManager(Allocator alloc, const INativeTypeHost *nth, const ICodeProvider *cp);
			virtual ~RDXObjectManager();

			// Serializer implementation that does nothing but propagate marks
			class GarbageCollectionSerializer : public ISerializer
			{
			private:
				GCLink _scanGCL;
				GCLink _liveGCL;
				void *_tailLink;

			public:
				GarbageCollectionSerializer(GCLink scanGCL, GCLink liveGCL, void *tailLink);
				bool TryIncludeObject(const void *obj);
				void SerializeReference(void *obj);
				void SerializeData(Type *type, const void *data);
				void SerializeBulk(const void *data, LargeInt sz);
			};

			
			class FileWriteSerializer : public ISerializer
			{
			private:
				Domain _targetDomain;
				IObjectManager *_objm;

			public:
				FileWriteSerializer(Domain targetDomain, IObjectManager *objm);

				bool TryIncludeObject(const void *obj);
				void SerializeReference(void *obj);
				void SerializeBulk(const void *data, LargeInt sz);
				void SerializeData(Type *type, const void *data);
			};

			void MarkObject(const void *obj, ISerializer *ser, ScanID scanID, GCLink gcl, bool refsFinalized);
			bool RefIsShell(const void *ref);

			template<class _RT>
			_RT *DeshellRef(_RT *ref);

			
			void *GetLocalResourcesMap();
			void *GetImportedResourcesMap();
			void Shutdown();

			// TODO: This is stupid, these should be members of something else
			const String *DeserializeTextString(OperationContext *ctx, IO::ITextDeserializer *td);
			const String *DeserializeBinaryString(OperationContext *ctx, IO::IFileStream *reader, Package *pkg);
			void SerializeBinaryString(const String *str, IO::IFileStream *fs, const SSIDTable *ssidTable) const;
			void SerializeTextString(const String *str, IO::IFileStream *fs) const;

			void *ResolveShellableReference(void *ref) const;
			const void *ResolveShellableReference(const void *ref) const;
			void GraphDependencies(void *obj, ISerializer *ser, ScanID scanID, GCLink gcl, bool markNative);
			void StartSerialize(ISerializer *ser, GCLink gcl);
			void FinishSerialize(ISerializer *ser, GCLink gcl, bool markNative);
			void SerializeIncludeObject(ISerializer *ser, const void *tobj, GCLink gcl);
			void SerializeIncludeStructure(ISerializer *ser, const StructuredType *st, const void *obj, GCLink gcl);
			void AuditSentinels();
			void InitializeCoreMutexes(OperationContext *ctx);

			Threading::IMutex *GetCoreMutex(int mNum);
			void IncrementThreadCounter();

			void DecrementThreadCounter();
			void BeginBlockingOperation(OperationContext *ctx, int mNum);
			void EndBlockingOperation(OperationContext *ctx, int mNum);

			void AddPersistentObject(CRef<void> *cref, void *obj);
			void RemovePersistentObject(CRef<void> *cref);

			const INativeTypeHost *GetTypeHost() const;
			const ICodeProvider *GetCodeProvider() const;
			Allocator *GetAllocator();

			void CollectGarbage(OperationContext *ctx);
			void SetCollectionFrequency(NonAtomicInt frequency);
			void SetILDisposal(bool shouldDispose);
			GCInfo *FirstLiveObject();
			GCInfo *NextLiveObject(GCInfo *gci);

			struct StructuredTypeProcessor : public ITypeProcessor
			{
				void Finalize(void *obj, IObjectManager *objm) const;
				bool OnLoad(OperationContext *ctx, void *obj, IObjectManager *objm) const;
				void MarkDependencies(IObjectManager *objm, void *obj, const StructuredType *st,
					bool markNative, ISerializer *ser, ScanID scanID, GCLink gcl) const;
				static StructuredTypeProcessor instance;
			};

			static void ParseNumber(String *str, Long *pAboveDec, Long *pBelowDec, Long *pFractionDivisor);

			struct BoolSerializer : public ITypeSerializer
			{
				void DeserializeTextInstance(OperationContext *ctx, IObjectManager *objm, void *instance, IO::ITextDeserializer *td, IPackageHost *host, Package *pkg) const;
				void DeserializeBinaryInstance(OperationContext *ctx, IObjectManager *objm, void *instance, IO::IFileStream *reader, IPackageHost *host, Package *pkg) const;
				
				void SerializeBinaryInstance(IObjectManager *objm, const void *obj, IO::IFileStream *fs, const ObjectManagement::SSIDTable *ssidTable) const;
				void SerializeTextInstance(IObjectManager *objm, const void *obj, IO::IFileStream *fs, const ObjectManagement::SSIDTable *ssidTable) const;

				static BoolSerializer instance;
			};

			struct StringProcessor : public ITypeProcessor
			{
				void Finalize(void *obj, IObjectManager *objm) const;
				bool OnLoad(OperationContext *ctx, void *obj, IObjectManager *objm) const;
				void MarkDependencies(IObjectManager *objm, void *obj, const StructuredType *st, bool markNative, ISerializer *ser, ScanID scanID, GCLink gcl) const;
				static StringProcessor instance;
			};

			struct StringSerializer : public ITypeSerializer
			{
				void DeserializeTextInstance(OperationContext *ctx, IObjectManager *objm, void *instance, IO::ITextDeserializer *td, IPackageHost *host, Package *pkg) const;
				void DeserializeBinaryInstance(OperationContext *ctx, IObjectManager *objm, void *instance, IO::IFileStream *reader, IPackageHost *host, Package *pkg) const;
				
				void SerializeBinaryInstance(IObjectManager *objm, const void *obj, IO::IFileStream *fs, const ObjectManagement::SSIDTable *ssidTable) const;
				void SerializeTextInstance(IObjectManager *objm, const void *obj, IO::IFileStream *fs, const ObjectManagement::SSIDTable *ssidTable) const;

				static StringSerializer instance;
			};

			struct MethodProcessor : public ITypeProcessor
			{
				void MarkDependencies(IObjectManager *objm, void *obj, const StructuredType *st, bool markNative, ISerializer *ser, ScanID scanID, GCLink gcl) const;
				void Finalize(void *obj, IObjectManager *objm) const;
				bool OnLoad(OperationContext *ctx, void *obj, IObjectManager *objm) const;
				static MethodProcessor instance;
			};

			BuiltIns *GetBuiltIns();
			const BuiltIns *GetBuiltIns() const;
			bool MethodOverrideCompatible(const StructuredType *implementingType, const Method *base, const Method *ov);
			void ValidateStructures(OperationContext *ctx);
			void ValidateStructure(OperationContext *ctx, StructuredType *st);
			bool ResolveStructure(OperationContext *ctx, StructuredType *st);
			void InitializeBuiltInTypes(OperationContext *ctx);

			LargeInt TypeElementSize(const Type *t);
			CRef<void> CreateContainer(OperationContext *ctx, LargeInt elementSize, LargeInt numElements, Int numDimensions,
				Domain domain, const Type *t, const ITypeProcessor *tp, LargeInt overflow);
			CRef<const String> CreateStringFromCS(OperationContext *ctx, CandidateString *cs, bool lookupOnly);
			CRef<const String> CreateStringASCII(OperationContext *ctx, const char *str, LargeInt size = -1, bool lookupOnly = false);
			CRef<const String> CreateString(OperationContext *ctx, const Char *str, LargeInt numChars, bool lookupOnly = false);
			CRef<const String> CreateStringUTF8(OperationContext *ctx, const Byte *str, LargeInt size, bool lookupOnly = false);
			CRef<const String> CreateStringConcatenated(OperationContext *ctx, const String *str1, const String *str2);
			CRef<const String> CreateStringSub(OperationContext *ctx, const String *str, LargeInt startIndex, LargeInt length = -1);
			CRef<RuntimeThread> CreateThread(OperationContext *ctx, LargeInt stackSize);
			void AddUnloadedObject(OperationContext *ctx, void *obj);
			void AddGlobalSymbol(OperationContext *ctx, const String *symbolName, void *object);
			Domain HostGetSymbolDomain(String *symbol);
			bool ResolveImports(OperationContext *ctx, IPackageHost *host);
			bool TypeIsValid(const Type *t) const;
			bool ObjectIsConstant(const void *obj) const;
			bool TypeIsObjectReference(const Type *t) const;
			bool TypeCanBeTraced(const Type *t) const;
			bool RefTypesCompatibleRecursive(const Type *from, const Type *to, const Type *initialFrom, int depth) const;
			bool NonRefTypesCompatible(const Type *from, const Type *to) const;
			bool TypesCompatible(const Type *from, const Type *to) const;
			bool TypesCompatiblePolymorphic(const Type *from, const Type *to) const;
			bool ObjectCompatible(const void *from, const Type *to) const;
			bool EnumCompatible(EnumValue ev, const Enumerant *enums) const;
			void TypeValueSize(OperationContext *ctx, const Type *t, LargeInt &size, LargeInt &align) const;
			void ResolveObjectInteriorReferences(OperationContext *ctx, void *obj, bool finalStep);
			void ResolveInteriorReferences(OperationContext *ctx, bool finalStep);
			bool ResolveStructureDefault(OperationContext *ctx, StructuredType *st);
			void VerifyDuplicates(OperationContext *ctx, IPackageHost *packageHost);
			void LoadSymbolsOfCriticality(OperationContext *ctx, IPackageHost *packageHost, bool criticality);
			CRef<Package> LoadSinglePackage(OperationContext *ctx, Domain domain, IPackageHost *packageHost);
			void HardenStructures(OperationContext *ctx);
			void FinishPackageLoad(OperationContext *ctx);

			void FinishDeserialize(OperationContext *ctx, IPackageHost *host);	// Runs after LoadSinglePackage

			CRef<Package> LoadPackage(OperationContext *ctx, Domain domain, IPackageHost *packageHost);
			CRef<void> LoadObject(OperationContext *ctx, IPackageHost *packageHost);	// Returns the first symbol in the DOMAIN_Runtime package from packageHost

			void SavePackage(OperationContext *ctx, Domain domain, IPackageHost *packageHost);
			void SaveObject(OperationContext *ctx, const void *object, IO::IFileStream *fs, bool isText);
			void SavePackageFile(OperationContext *ctx, Domain domain, IO::IFileStream *fs,
				const void *object, SaveMode saveMode, bool isText);

			void RegisterPackage(OperationContext *ctx, Domain domain, Package *pkg);
			bool PackageLoaded(Domain domain);
			CRef<ArrayOfType> CreateArrayType(OperationContext *ctx, Type *t, LargeInt numDimensions, bool constant);
			CRef<void> LookupSymbolSimple(OperationContext *ctx, const String *symbolName);
			CRef<void> LookupSymbol(OperationContext *ctx, const String *symbolName, IPackageHost *packageHost);

			void DebugDumpGST();
		};
	}
}


// ==============================================================================================
namespace RDX
{
	namespace ObjectManagement
	{
		using namespace RDX::Collections;

		NumericTypeSerializer<LargeInt, BinPackageLargeInt> i_LargeIntSerializer;
		NumericTypeSerializer<Int, Int> i_IntSerializer;
		NumericTypeSerializer<Char, Char> i_CharSerializer;
		NumericTypeSerializer<Byte, Byte> i_ByteSerializer;

		Char CandidateString::DecodeCharacter(const void **pData, LargeInt *pAvailableBytes) const
		{
			switch(format)
			{
			case CSF_UTF8:
				{
					return Utility::DecodeUTF8Char(pData, pAvailableBytes);
				}
				break;
			case CSF_ASCII:
				{
					const char *pASCII = static_cast<const char *>(*pData);

					if(pASCII[0] & 0x80)
						return CHAR_Invalid;

					(*pAvailableBytes)--;
					*pData = pASCII+1;
					return static_cast<Char>(pASCII[0]);
				}
				break;
			case CSF_Char:
				{
					const Char *pChar = static_cast<const Char *>(*pData);
					(*pAvailableBytes) -= sizeof(Char);
					*pData = pChar+1;
					return pChar[0];
				}
				break;
			case CSF_Concatenated:
				{
					const Char *pChar = static_cast<const Char *>(*pData);
					LargeInt availableBytes = *pAvailableBytes - static_cast<LargeInt>(sizeof(Char));
					if(availableBytes == numBytes2)
						*pData = static_cast<const Char *>(bytes2);
					else
						*pData = pChar + 1;
					*pAvailableBytes = availableBytes;
					return pChar[0];
				}
				break;
			}

			return CHAR_Invalid;
		}

		// Returns true if the string is valid
		bool CandidateString::CountCharacters()
		{
			LargeInt availableBytes = numBytes;
			const void *data = bytes;

			
			if(format == CSF_Concatenated || format == CSF_Char)
			{
				numCharacters = numBytes / static_cast<LargeInt>(sizeof(Char));
				return true;
			}
			if(format == CSF_ASCII)
			{
				numCharacters = numBytes;
				return true;
			}

			numCharacters = 0;

			while(availableBytes > 0)
			{
				Char c = DecodeCharacter(&data, &availableBytes);
				if(c == (Char)(-1))
					break;
				numCharacters++;
			}

			return availableBytes == 0;
		}


		inline void HashMapStringTable::InitializeElement(MyHashEntry *v)
		{
			memset(v, 0, sizeof(MyHashEntry));
		}

		inline LargeInt HashMapStringTable::UnitSize() const
		{
			return sizeof(MyHashEntry);
		}

		inline bool HashMapStringTable::CompareKey(const CandidateString *cs, const HashEntry<Char*, const String*> *e) const
		{
			const Char *ekv = e->k;

			const void *csData = cs->bytes;
			LargeInt csBytesRemaining = cs->numBytes;

			if(cs->format == CandidateString::CSF_Char)
				return (cs->numCharacters == GCInfo::From(e->k)->numElements) && !memcmp(csData, ekv, sizeof(Char)*cs->numCharacters);
			else
			{
				if(cs->numCharacters != GCInfo::From(e->k)->numElements)
					return false;

				if(cs->format == CandidateString::CSF_ASCII)
				{
					LargeInt nChars = cs->numCharacters;
					const char *asciiChar = static_cast<const char *>(csData);
					for(LargeInt i=0;i<nChars;i++)
					{
						if(ekv[i] != static_cast<Char>(asciiChar[i]))
							return false;
					}
				}
				else if(cs->format == CandidateString::CSF_Char)
				{
					LargeInt nChars = cs->numCharacters;
					const Char *csChars = static_cast<const Char *>(csData);
					for(LargeInt i=0;i<nChars;i++)
					{
						if(ekv[i] != csChars[i])
							return false;
					}
				}

				while(csBytesRemaining)
				{
					Char csc = cs->DecodeCharacter(&csData, &csBytesRemaining);
					if (csc != *ekv)
						return false;
					ekv++;
				}
			}

			return true;
		}

		inline HashValue HashMapStringTable::HashCKey(const void *ckey) const
		{
			const CandidateString *cs = static_cast<const CandidateString *>(ckey);

			if(cs->format == CandidateString::CSF_Char)
				return Utility::HashBytes(cs->bytes, sizeof(Char)*cs->numCharacters);
			else
			{
				RDX::Utility::IntermediateHash hv;

				const void *csData = cs->bytes;
				LargeInt csBytesRemaining = cs->numBytes;

				while(csBytesRemaining)
				{
					Char c = cs->DecodeCharacter(&csData, &csBytesRemaining);
					hv.FeedBytes(&c, sizeof(Char));
				}
				return hv.Flush();
			}
		}

		inline Char *HashMapStringTable::ConstructKey(OperationContext *ctx, const void *ckey, bool &recheck)
		{
			const CandidateString *cs = static_cast<const CandidateString *>(ckey);
			recheck = true;

			CRef<Char> carray;
			
			RDX_TRY(ctx)
			{
				RDX_PROTECT_ASSIGN(ctx, carray, _native.objectManager->Create1DArray<Char>(ctx, cs->numCharacters, _aot_ConstChar, NULL, DOMAIN_Runtime, 1));
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROWV(ctx, NULL);
			}
			RDX_ENDTRY

			GCInfo::From(carray)->gcflags |= GCInfo::GCOF_ConstantArray;

			if(cs->format == CandidateString::CSF_Char)
				BlockCopy(carray, cs->bytes, sizeof(Char) * (cs->numCharacters));
			else
			{
				const void *csData = cs->bytes;
				LargeInt csBytesRemaining = cs->numBytes;

				Char *kv = carray;

				while(csBytesRemaining)
				{
					*kv = cs->DecodeCharacter(&csData, &csBytesRemaining);
					kv++;
				}
			}
			carray[cs->numCharacters] = 0;

			const_cast<CandidateString *>(cs)->feedback = carray;
			return carray;
		}

		RDXObjectManager::RDXObjectManager(Allocator alloc, const INativeTypeHost *nth, const ICodeProvider *cp)
		{
			_allocator = alloc;
			_nth = nth;
			_codeProvider = cp;

			Threading::NonAtomicWrite(&_stringReadAttempts, 0);
			Threading::NonAtomicWrite(&_stringWriteAttempts, 0);

			_stringTable.SetObjectManager(this);
			_gst.SetObjectManager(this);
			_packages.SetObjectManager(this);
			_parseLocalResources.SetObjectManager(this);
			_parseImportedResources.SetObjectManager(this);

			_liveSetGCL = GCL_Objects1;
			_scanSetGCL = GCL_Objects2;
			_currentScanID = static_cast<ScanID>(0) - 1;
			_initialized = false;

			Threading::NonAtomicWrite(&_activeThreadCount, 0);

#ifdef RDX_ENABLE_SMP
			_ignoreMutexesDuringSyncs = false;
			for(int i=0;i<COREMUTEX_Count;i++)
				_operationsActive[i] = false;
#endif

			_forcePackagesRelevant = false;

			for(int i=0;i<GCL_Count;i++)
			{
				_linkHead.prev[i] = NULL;
				_linkHead.next[i] = &_linkTail;
				_linkTail.next[i] = NULL;
				_linkTail.prev[i] = &_linkHead;
			}

			_gcFrequency = 500;
			Threading::AtomicWrite(&_gcCounter, 0);

			_crefLinkHead = NULL;

			_linkHead.gcflags = GCInfo::GCOF_LinkTerminator;
			_linkTail.gcflags = GCInfo::GCOF_LinkTerminator;

			_shouldDisposeIL = true;

			_pendingDeshellObjects.EvictAll();
			_pendingProcessObjects.EvictAll();
			_unloadedPackages.EvictAll();
		}

		RDXObjectManager::~RDXObjectManager()
		{
		}

		RDXObjectManager::FileWriteSerializer::FileWriteSerializer(Domain targetDomain, IObjectManager *objm)
		{
			_targetDomain = targetDomain;
			_objm = objm;
		}

		bool RDXObjectManager::FileWriteSerializer::TryIncludeObject(const void *obj)
		{
			if(!obj) return false;

			const GCInfo *info = GCInfo::From(obj);

			if(info->containerType == _objm->GetBuiltIns()->st_String)
				return true;	// Always need strings

			if(info->domain == _targetDomain
				|| info->domain == DOMAIN_Runtime
				|| info->domain == DOMAIN_Duplicable)
			{
				return true;
			}
			return false;
		}

		void RDXObjectManager::FileWriteSerializer::SerializeReference(void *obj)
		{
		}

		void RDXObjectManager::FileWriteSerializer::SerializeBulk(const void *data, LargeInt sz)
		{
		}

		void RDXObjectManager::FileWriteSerializer::SerializeData(Type *type, const void *data)
		{
		}

		RDXObjectManager::GarbageCollectionSerializer::GarbageCollectionSerializer(GCLink scanGCL, GCLink liveGCL, void *tailLink)
		{
			_scanGCL = scanGCL;
			_liveGCL = liveGCL;
			_tailLink = tailLink;
		}

		bool RDXObjectManager::GarbageCollectionSerializer::TryIncludeObject(const void *obj)
		{
			// Remove from the condemned set
			const_cast<GCInfo*>(GCInfo::From(obj))->Unlink(_liveGCL);
			return true;
		}

		void RDXObjectManager::GarbageCollectionSerializer::SerializeReference(void *obj)
		{
		}

		void RDXObjectManager::GarbageCollectionSerializer::SerializeData(Type *type, const void *data)
		{
		}

		void RDXObjectManager::GarbageCollectionSerializer::SerializeBulk(const void *data, LargeInt sz)
		{
		}

		inline void RDXObjectManager::MarkObject(const void *obj, ISerializer *ser, ScanID scanID, GCLink gcl, bool refsFinalized)
		{
			if(!refsFinalized)
				obj = ResolveShellableReference(obj);

			if(obj == NULL)
				return;

			const GCInfo *objGCI = GCInfo::From(obj);

			if(objGCI->serializeScanID == scanID)
				return;		// Already tagged this

			objGCI->serializeScanID = scanID;

			// Mark this as an inclusion
			const_cast<GCInfo*>(objGCI)->LinkBefore(&_linkTail, gcl);
			_scanObjectCounter[gcl]++;

			// Flag as external
			if(ser->TryIncludeObject(obj))
				objGCI->gcflags &= (~GCInfo::GCOF_External);
			else
				objGCI->gcflags |= GCInfo::GCOF_External;
		}

		bool RDXObjectManager::RefIsShell(const void *ref)
		{
			return ref != NULL && GCInfo::From(ref)->targetType == TargetableObject::TT_Shell;
		}

		template<class _RT>
		_RT *RDXObjectManager::DeshellRef(_RT *ref)
		{

			if(ref && GCInfo::From(ref)->targetType == TargetableObject::TT_Shell)
				return reinterpret_cast<_RT*>(reinterpret_cast<UnloadedObject*>(GCInfo::From(ref))->resolution);
			return ref;
		}
		

		const void *RDXObjectManager::ResolveShellableReference(const void *ref) const
		{
			if(ref && GCInfo::From(ref)->targetType == TargetableObject::TT_Shell)
			{
				const UnloadedObject *uo = reinterpret_cast<const UnloadedObject*>(GCInfo::From(ref));
				return uo->resolution;
			}
			return ref;
		}

		void *RDXObjectManager::ResolveShellableReference(void *ref) const
		{
			if(ref && GCInfo::From(ref)->targetType == TargetableObject::TT_Shell)
			{
				const UnloadedObject *uo = reinterpret_cast<const UnloadedObject*>(GCInfo::From(ref));
				return uo->resolution;
			}
			return ref;
		}

		void RDXObjectManager::GraphDependencies(void *obj, ISerializer *ser, ScanID scanID, GCLink gcl, bool markNative)
		{
			GCInfo *info = GCInfo::From(obj);
			bool refsFinalized = ((info->gcflags & GCInfo::GCOF_ReferencesMayBeShells) == 0);

			if(info->containerType && !info->containedStructure)
			{
				// Reference list
				void **asArray = reinterpret_cast<void**>(obj);
				for(LargeInt i=0;i<info->numElements;i++)
					MarkObject(asArray[i], ser, scanID, gcl, refsFinalized);
			}
			else
			{
				// Feed the structure through its type processor
				const ITypeProcessor *tp = info->typeProcessor;
				LargeInt elementSize = info->elementSize;
				LargeInt nElements = info->numElements;

				if(tp)
				{
					const StructuredType *st = info->containedStructure;
					UInt8 *arrayBytes = reinterpret_cast<UInt8*>(ResolveShellableReference(obj));
					for(LargeInt i=0;i<nElements;i++)
						tp->MarkDependencies(this, arrayBytes + elementSize*i,
							info->containedStructure, markNative, ser, scanID, gcl);
				}

				// Scan out references from the reference layout table
				if(info->containedStructure)
				{
					const StructuredType::NativeProperties::ContainedReference *refs = info->containedStructure->_native.containedReferences;

					if(refs)
					{
						LargeInt nRefs = GCInfo::From(refs)->numElements;

						for(LargeInt i=0;i<nElements;i++)
						{
							UInt8 *base = reinterpret_cast<UInt8*>(obj) + elementSize*i;
							for(LargeInt j=0;j<nRefs;j++)
							{
								void **refp = reinterpret_cast<void**>(base + refs[j].offset);
								void *ref = *refp;

								MarkObject(ResolveShellableReference(ref), ser, scanID, gcl, refsFinalized);
							}
						}
					}
				}
			}

			// Also mark anything referenced by this object
			MarkObject(info->containerType, ser, scanID, gcl, refsFinalized);
			MarkObject(info->containedStructure, ser, scanID, gcl, refsFinalized);
			MarkObject(info->contentsType, ser, scanID, gcl, refsFinalized);
			MarkObject(info->gstSymbol, ser, scanID, gcl, refsFinalized);

			if(markNative)
				MarkObject(info->package, ser, scanID, gcl, refsFinalized);
		}

		void RDXObjectManager::StartSerialize(ISerializer *ser, GCLink gcl)
		{
			_currentScanID++;

			// Remark all object scan IDs, this happens on first run and if scan ID overflows
			if(_currentScanID == 0)
			{
				GCInfo *obj = _linkHead.next[_liveSetGCL];

				while(obj != &_linkTail)
				{
					obj->serializeScanID = 0;
					obj = obj->next[_liveSetGCL];
				}
				_currentScanID++;	// Can't scan on 0 because objects are initialized on 0
			}

			// Empty the target set
			_linkHead.next[gcl] = &_linkTail;
			_linkTail.prev[gcl] = &_linkHead;
			_scanObjectCounter[gcl] = 0;
		}

		void RDXObjectManager::FinishSerialize(ISerializer *ser, GCLink gcl, bool markNative)
		{
			GCInfo *scanObj = _linkHead.next[gcl];

			while(scanObj != &_linkTail)
			{
				if(!(scanObj->gcflags & GCInfo::GCOF_External))
					GraphDependencies(&scanObj->_objectData, ser, _currentScanID, gcl, markNative);

				// Might introduce new objects to the scan
				scanObj = scanObj->next[gcl];
			}
		}

		void RDXObjectManager::SerializeIncludeObject(ISerializer *ser, const void *tobj, GCLink gcl)
		{
			const void *obj = this->ResolveShellableReference(tobj);
			if(obj == NULL)
				return;

			MarkObject(obj, ser, _currentScanID, gcl, (GCInfo::From(obj)->gcflags & GCInfo::GCOF_ReferencesMayBeShells) == 0);
		}

		void RDXObjectManager::SerializeIncludeStructure(ISerializer *ser, const StructuredType *st, const void *obj, GCLink gcl)
		{
			if(st->storageSpecifier == EnumValue::From(StructuredType::SS_RefStruct) || st->storageSpecifier == EnumValue::From(StructuredType::SS_ValStruct))
			{
				LargeInt ncr = st->_native.numContainedReferences;
				if(ncr)
				{
					for(LargeInt cri=0;cri<ncr;cri++)
					{
						LargeInt offset = st->_native.containedReferences[cri].offset;
						SerializeIncludeObject(ser, *reinterpret_cast<void*const*>(reinterpret_cast<const UInt8*>(obj) + offset), gcl);
					}
				}
			}
		}

		void RDXObjectManager::AuditSentinels()
		{
#ifdef RDX_ENABLE_SENTINELS
			GCInfo *link = _linkHead.next[_liveSetGCL];
			while(link != &_linkTail)
			{
				UInt32 s1 = link->sentinel1;
				UInt32 s2 = link->sentinel2[0];
				if(s1 != 0xdeadbeef || s2 != 0xdeadbeef)
					Utility::DebugBreak(Utility::BREAKCAUSE_SentinelAuditFailed);
				if(link->next[_liveSetGCL] && link->next[_liveSetGCL]->prev[_liveSetGCL] != link)
					Utility::DebugBreak(Utility::BREAKCAUSE_SentinelAuditFailed);
				link = link->next[_liveSetGCL];
			}
#endif
		}

		GCInfo *RDXObjectManager::FirstLiveObject()
		{
			return _linkHead.next[_liveSetGCL];
		}
		
		GCInfo *RDXObjectManager::NextLiveObject(GCInfo *gci)
		{
			return gci->next[_liveSetGCL];
		}

		void RDXObjectManager::InitializeCoreMutexes(OperationContext *ctx)
		{
#ifdef RDX_ENABLE_SMP
			RDX_TRY(ctx)
			{
				_ignoreMutexesDuringSyncs = true;
				for(int i=0;i<COREMUTEX_Count;i++)
					RDX_PROTECT_ASSIGN(ctx, _coreMutexes[i], Threading::CreateMutex(ctx, this) );
				_ignoreMutexesDuringSyncs = false;
			}
			RDX_CATCH(ctx)
			{
				_ignoreMutexesDuringSyncs = false;
				RDX_RETHROW(ctx);
			}
			RDX_ENDTRY
#endif
		}

		Threading::IMutex *RDXObjectManager::GetCoreMutex(int mNum)
		{
#ifdef RDX_ENABLE_SMP
			return _coreMutexes[mNum];
#else
			return NULL;
#endif
		}

		void RDXObjectManager::IncrementThreadCounter()
		{
#ifdef RDX_ENABLE_SMP
			_coreMutexes[COREMUTEX_GlobalOperation]->Acquire(0);
#endif
			Threading::AtomicIncrement(&_activeThreadCount);
#ifdef RDX_ENABLE_SMP
			_coreMutexes[COREMUTEX_GlobalOperation]->Release();
#endif
		}

		void RDXObjectManager::DecrementThreadCounter()
		{
			Threading::AtomicDecrement(&_activeThreadCount);
		}

		void RDXObjectManager::BeginBlockingOperation(OperationContext *ctx, int mNum)
		{
#ifdef RDX_ENABLE_SMP
			bool acquiredOp = false;
			while(!acquiredOp)
			{
				ctx->Acquire(this, COREMUTEX_OperationCheck);
				bool blockGlobal = _operationsActive[COREMUTEX_GlobalOperation];

				if(blockGlobal)
				{
					// Stop this operation and block on the global operation until it finishes
					Threading::AtomicDecrement(&_activeThreadCount);
					ctx->Release(this, COREMUTEX_OperationCheck);
					ctx->Acquire(this, COREMUTEX_GlobalOperation);
					Threading::AtomicIncrement(&_activeThreadCount);
					ctx->Release(this, COREMUTEX_GlobalOperation);
					continue;
				}

				acquiredOp = ctx->TryAcquire(this, mNum);
				ctx->Release(this, COREMUTEX_OperationCheck);
			}

			// Successfully acquired
			if(mNum == COREMUTEX_GlobalOperation)
			{
				// Spin until all other threads stop
				while(Threading::AtomicRead(&_activeThreadCount) != 1)
				{
				}
				Threading::Synchronize();
			}
#endif
		}

		void RDXObjectManager::EndBlockingOperation(OperationContext *ctx, int mNum)
		{
#ifdef RDX_ENABLE_SMP
			_operationsActive[mNum] = false;
			ctx->Release(this, mNum);
#endif
		}

		void RDXObjectManager::AddPersistentObject(CRef<void> *cref, void *obj)
		{
#ifdef RDX_ENABLE_SMP
			if(!_ignoreMutexesDuringSyncs)
				_coreMutexes[COREMUTEX_PersistentObjectList]->Acquire(0);
#endif

			cref->Link(obj, &_crefLinkHead);

#ifdef RDX_ENABLE_SMP
			if(!_ignoreMutexesDuringSyncs)
				_coreMutexes[COREMUTEX_PersistentObjectList]->Release();
#endif
		}

		void RDXObjectManager::RemovePersistentObject(CRef<void> *cref)
		{
#ifdef RDX_ENABLE_SMP
			if(!_ignoreMutexesDuringSyncs)
				_coreMutexes[COREMUTEX_PersistentObjectList]->Acquire(0);
#endif

			cref->Unlink(&_crefLinkHead);

#ifdef RDX_ENABLE_SMP
			if(!_ignoreMutexesDuringSyncs)
				_coreMutexes[COREMUTEX_PersistentObjectList]->Release();
#endif
		}

		const INativeTypeHost *RDXObjectManager::GetTypeHost() const
		{
			return _nth;
		}

		const ICodeProvider *RDXObjectManager::GetCodeProvider() const
		{
			return this->_codeProvider;
		}

		Allocator *RDXObjectManager::GetAllocator()
		{
			return &this->_allocator;
		}

		void *RDXObjectManager::GetLocalResourcesMap()
		{
			return &_parseLocalResources;
		}

		void *RDXObjectManager::GetImportedResourcesMap()
		{
			return &_parseImportedResources;
		}


		void RDXObjectManager::Shutdown()
		{
			// Delete everything in the live set
			GCInfo *current = _linkHead.next[_liveSetGCL];
			while(!(current->gcflags & GCInfo::GCOF_LinkTerminator))
			{
				GCInfo *next = current->next[_liveSetGCL];
				if(current->typeProcessor)
					current->typeProcessor->Finalize(&current->_objectData, this);
				_allocator.Free(current);
				current = next;
			}

			// Clear all linked references
			while(_crefLinkHead != NULL)
				_crefLinkHead->Unlink(&_crefLinkHead);

			Allocator alloc = _allocator;

			// Destroy all members
			this->~RDXObjectManager();

			// Release everything
			alloc.Free(this);
		}
		
		void RDXObjectManager::SetCollectionFrequency(NonAtomicInt frequency)
		{
			this->_gcFrequency = frequency;
		}
		
		void RDXObjectManager::SetILDisposal(bool shouldDispose)
		{
			this->_shouldDisposeIL = shouldDispose;
		}


		inline void RDXObjectManager::IncludeGCList(ISerializer &gc, GCObjectList *gcol)
		{
			for(LargeInt oi=0;oi<gcol->numObjects;oi++)
			{
				if(gcol->objects[oi] == NULL) continue;
				SerializeIncludeObject(&gc, &gcol->objects[oi]->_objectData, _scanSetGCL);
			}
			SerializeIncludeObject(&gc, gcol->objects, _scanSetGCL);
		}

		void RDXObjectManager::CollectGarbage(OperationContext *ctx)
		{
			BeginBlockingOperation(ctx, COREMUTEX_GlobalOperation);

			GarbageCollectionSerializer gc(_scanSetGCL, _liveSetGCL, &_linkTail._objectData);

			StartSerialize(&gc, _scanSetGCL);

			{
#ifdef RDX_ENABLE_SMP
				Threading::MutexLock<Threading::IMutex> _(_coreMutexes[COREMUTEX_PersistentObjectList]);
#endif

				// Move all root objects to the scan set
				const CRef<void> *link = _crefLinkHead;
				while(link != NULL)
				{
					SerializeIncludeObject(&gc, link->Object(), _scanSetGCL);
					link = link->Next();
				}
			}

			if(_forcePackagesRelevant)
			{
				// There are unloaded packages
				IncludeGCList(gc, &_unloadedPackages);
				IncludeGCList(gc, &_pendingDeshellObjects);
				IncludeGCList(gc, &_pendingProcessObjects);
			}

			// Include all code provider dictionary objects
			if(_builtins.providerDictionary)
			{
				LargeInt numEDX = _builtins.providerDictionaryTracedSymbolCount;
				SerializeIncludeObject(&gc, _builtins.providerDictionary, _scanSetGCL);
				for(LargeInt i=0;i<numEDX;i++)
					SerializeIncludeObject(&gc, _builtins.providerDictionary[i], _scanSetGCL);
			}

			// Include any in-progress load data
			{
				Collections::HashMap<HashMapSimple<const String*, LoadShell> > *manifests[2] = { &this->_parseImportedResources, &this->_parseLocalResources };

				for(int m=0;m<2;m++)
				{
					Collections::HashMap<HashMapSimple<const String*, LoadShell> > *manifest = manifests[m];

					if(manifest->_native.untracedEntries)
					{
						HashEntry<const String *, LoadShell> *entries = manifest->_native.untracedEntries;
						LargeInt numEntries = manifest->_native.numEntries;
						for(LargeInt i=0;i<numEntries;i++)
						{
							if(entries[i].e.elementType > HashElement::HMT_ContainsData)
							{
								SerializeIncludeObject(&gc, entries[i].k, _scanSetGCL);
								SerializeIncludeObject(&gc, entries[i].v.typeName, _scanSetGCL);
							}
						}
					}
				}
			}

			// Include any persistent packages
			if(_packages._native.untracedEntries)
			{
				HashEntry<Domain, Package*> *entries = _packages._native.untracedEntries;
				LargeInt numEntries = _packages._native.numEntries;
				for(LargeInt i=0;i<numEntries;i++)
				{
					if(entries[i].e.elementType > HashElement::HMT_ContainsData)
					{
						const Package *pkg = static_cast<const Package *>(ResolveShellableReference(entries[i].v));

						if(pkg && pkg->_native.persistence == Package::PERS_Persistent)
							SerializeIncludeObject(&gc, pkg, _scanSetGCL);
					}
				}
			}

			// Finalize dependency graph
			FinishSerialize(&gc, _scanSetGCL, true);

			// Remove dead strings
			if(_stringTable._native.untracedEntries)
			{
				HashEntry<Char*, const String*> *entries = _stringTable._native.untracedEntries;
				LargeInt numEntries = _stringTable._native.numEntries;
				for(LargeInt i=0;i<numEntries;i++)
				{
					if(entries[i].e.elementType > HashElement::HMT_ContainsData &&
						GCInfo::From(entries[i].v)->serializeScanID != _currentScanID)
					{
						_stringTable.RemoveEntry(i);
					}
				}
				_stringTable.Balance();
			}

			// Remove dead global symbols
			if(_gst._native.untracedEntries)
			{
				HashEntry<const String*, void*> *entries = _gst._native.untracedEntries;
				LargeInt numEntries = _gst._native.numEntries;
				for(LargeInt i=0;i<numEntries;i++)
				{
					if(entries[i].e.elementType > HashElement::HMT_ContainsData)
					{
						void *entry = ResolveShellableReference(entries[i].v);
						const GCInfo *entryGCI = GCInfo::From(entry);
						const GCInfo *symbolGCI = GCInfo::From(GCInfo::From(entry)->gstSymbol);

						if(entry && entryGCI->serializeScanID != _currentScanID)
							_gst.RemoveEntry(i);
					}
				}
				_gst.Balance();
			}

			// Remove dead packages
			if(_packages._native.untracedEntries)
			{
				HashEntry<Domain, Package*> *entries = _packages._native.untracedEntries;
				LargeInt numEntries = _packages._native.numEntries;
				for(LargeInt i=0;i<numEntries;i++)
				{
					if(entries[i].e.elementType > HashElement::HMT_ContainsData)
					{
						void *entry = ResolveShellableReference(entries[i].v);
						const GCInfo *entryGCI = GCInfo::From(entry);

						if(entry && entryGCI->serializeScanID != _currentScanID)
							_packages.RemoveEntry(i);
					}
				}
				_packages.Balance();
			}

			// Make the scanned set live
			GCLink temp = _liveSetGCL;
			_liveSetGCL = _scanSetGCL;
			_scanSetGCL = temp;

			// Delete everything in the condemned set
			// GCObject casts are just for debugging purposes
			GCInfo *current = _linkHead.next[_scanSetGCL];
			int objectsCollected = 0;
			while(!(current->gcflags & GCInfo::GCOF_LinkTerminator))
			{
				GCInfo *next = current->next[_scanSetGCL];
				if(current->typeProcessor)
					current->typeProcessor->Finalize(&current->_objectData, this);
				
				_allocator.Free(current);
				current = next;

				objectsCollected++;
			}

			_linkHead.next[_scanSetGCL] = &_linkTail;
			_linkTail.prev[_scanSetGCL] = &_linkHead;

			EndBlockingOperation(ctx, COREMUTEX_GlobalOperation);
		}

		void RDXObjectManager::StructuredTypeProcessor::Finalize(void *obj, IObjectManager *objm) const
		{
		}

		bool RDXObjectManager::StructuredTypeProcessor::OnLoad(OperationContext *ctx, void *obj, IObjectManager *objm) const
		{
			return true;
		}

		void RDXObjectManager::StructuredTypeProcessor::MarkDependencies(IObjectManager *objm, void *obj, const StructuredType *st,
			bool markNative, ISerializer *ser, ScanID scanID, GCLink gcl) const
		{
			StructuredType *mst = static_cast<StructuredType*>(obj);
			if(markNative)
			{
				objm->SerializeIncludeObject(ser, mst->_native.propertyOffsets, gcl);
				objm->SerializeIncludeObject(ser, mst->_native.containedReferences, gcl);
				objm->SerializeIncludeObject(ser, mst->_native.actualDefaultValue, gcl);

				if(mst->_native.containedReferences)
				{
					StructuredType::NativeProperties::ContainedReference *crs = mst->_native.containedReferences;
					LargeInt nRefs = GCInfo::From(crs)->numElements;
					for(LargeInt i=0;i<nRefs;i++)
						objm->SerializeIncludeObject(ser, crs->requiredType, gcl);
				}
			}
		}

		void RDXObjectManager::ParseNumber(String *str, Long *pAboveDec, Long *pBelowDec, Long *pFractionDivisor)
		{
			LargeInt nChars = str->Length();
			const Char *chars = str->AsChars();
			bool negative = false;
			bool pastDecimal = false;

			Long aboveDec, belowDec, fractionDivisor;

			aboveDec = 0;
			belowDec = 0;
			fractionDivisor = 1;

			for(LargeInt i=0;i<nChars;i++)
			{
				Char c = chars[i];
				if(c == '-')
					negative = true;
				else if(c == '.')
					pastDecimal = true;
				else
				{
					Long digit = c - '0';

					if(pastDecimal)
					{
						fractionDivisor = fractionDivisor * 10;
						belowDec = belowDec * static_cast<Long>(10) + digit;
					}
					else
						aboveDec = aboveDec * static_cast<Long>(10) + digit;
				}
			}

			if(negative)
			{
				aboveDec = -aboveDec;
				belowDec = -belowDec;
			}

			*pAboveDec = aboveDec;
			*pBelowDec = belowDec;
			*pFractionDivisor = fractionDivisor;
		}

		void RDXObjectManager::BoolSerializer::DeserializeTextInstance(OperationContext *ctx, IObjectManager *objm, void *instance, IO::ITextDeserializer *td, IPackageHost *host, Package *pkg) const
		{
			RDX_TRY(ctx)
			{
				CRef<const String> str;
				bool isString;
				RDX_PROTECT_ASSIGN(ctx, str, td->ParseToken(ctx, objm, &isString));
				if(str->Equal("true"))
					*static_cast<Bool*>(instance) = static_cast<Bool>(TrueValue);
				else
					*static_cast<Bool*>(instance) = static_cast<Bool>(FalseValue);
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROW(ctx);
			}
			RDX_ENDTRY
		}

		void RDXObjectManager::BoolSerializer::DeserializeBinaryInstance(OperationContext *ctx, IObjectManager *objm, void *instance, IO::IFileStream *reader, IPackageHost *host, Package *pkg) const
		{
			if(reader->ReadSwappableBytes(instance, sizeof(Bool)) != sizeof(Bool))
			{
				RDX_LTHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
			}
		}
		
		void RDXObjectManager::BoolSerializer::SerializeBinaryInstance(IObjectManager *objm, const void *obj, IO::IFileStream *fs, const ObjectManagement::SSIDTable *ssidTable) const
		{
			fs->WriteSwappableBytes(obj, sizeof(Bool));
		}

		void RDXObjectManager::BoolSerializer::SerializeTextInstance(IObjectManager *objm, const void *obj, IO::IFileStream *fs, const ObjectManagement::SSIDTable *ssidTable) const
		{
			if(*static_cast<const Bool*>(obj) != FalseValue)
				fs->WriteBytes(" true", 5);
			else
				fs->WriteBytes(" false", 6);
		}

		void RDXObjectManager::StringProcessor::Finalize(void *obj, IObjectManager *objm) const
		{
		}

		bool RDXObjectManager::StringProcessor::OnLoad(OperationContext *ctx, void *obj, IObjectManager *objm) const
		{
			return true;
		}

		void RDXObjectManager::StringProcessor::MarkDependencies(IObjectManager *objm, void *obj, const StructuredType *st,
			bool markNative, ISerializer *ser, ScanID scanID, GCLink gcl) const
		{
			if(!markNative)
				return;

			String *str = static_cast<String*>(obj);
			objm->SerializeIncludeObject(ser, str->AsChars(), gcl);
		}

		const String *RDXObjectManager::DeserializeTextString(OperationContext *ctx, IO::ITextDeserializer *td)
		{
			RDX_TRY(ctx)
			{
				CRef<const String> str;
				bool isString;
				RDX_PROTECT_ASSIGN(ctx, str, td->ParseToken(ctx, this, &isString));

				if(!isString)
					return NULL;
				else
					return str;
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROWV(ctx, NULL);
			}
			RDX_ENDTRY
		}

		void RDXObjectManager::StringSerializer::DeserializeTextInstance(OperationContext *ctx, IObjectManager *objm, void *instance, IO::ITextDeserializer *td, IPackageHost *host, Package *pkg) const
		{
			RDX_LTHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
		}

		void RDXObjectManager::StringSerializer::DeserializeBinaryInstance(OperationContext *ctx, IObjectManager *objm, void *instance, IO::IFileStream *reader, IPackageHost *host, Package *pkg) const
		{
			RDX_LTHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
		}

		const String *RDXObjectManager::DeserializeBinaryString(OperationContext *ctx, IO::IFileStream *reader, Package *pkg)
		{
			RDX_TRY(ctx)
			{
				LargeInt i;
				bool overflowed = false;
				bool readFailed = false;
				if(!reader->ReadConverted<BinPackageLargeInt, LargeInt>(&i, overflowed, readFailed))
				{
					if(overflowed)
						RDX_STHROW(ctx, Errors::RDX_ERROR_INTEGER_OVERFLOW);
					if(readFailed)
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
				}
				if(i < 0 || i == 1)
					RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
				if(i == 0)
					return NULL;
				else
				{
					i--;
					LargeInt numExports = GCInfo::From(pkg->_native.localSymbols)->numElements;
					if(i < numExports)
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
					i -= numExports;
					if(i >= GCInfo::From(pkg->_native.strings)->numElements)
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
					return pkg->_native.strings[i];
				}
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROWV(ctx, NULL);
			}
			RDX_ENDTRY
		}

		void RDXObjectManager::SerializeBinaryString(const String *str, IO::IFileStream *fs, const SSIDTable *ssidTable) const
		{
			LargeInt i = 0;
			if(str)
			{
				const GCInfo *info = GCInfo::From(str);
				StaticLookupPODKey<const GCInfo *> infoKey(info);
				i = *ssidTable->Lookup(infoKey);
			}
			fs->WriteConverted<LargeInt, BinPackageLargeInt>(i);
		}

		static void WriteEncodedStringBytes(IO::IFileStream *fs, const UInt8 *base, LargeInt nBase)
		{
			UInt8 refined[STRING_ENCODE_BACKLOG_SIZE*3];
			LargeInt sz = 0;
			for(LargeInt i=0;i<nBase;i++)
			{
				UInt8 b = base[i];
				if(b < 32)
				{
					refined[sz++] = '\\';
					refined[sz++] = static_cast<UInt8>('0' + b/10);
					refined[sz++] = static_cast<UInt8>('0' + b%10);
				}
				else if(b == 92)
				{
					refined[sz++] = '\\';
					refined[sz++] = '\\';
				}
				else if(b == 39)
				{
					refined[sz++] = '\\';
					refined[sz++] = '\'';
				}
				else
					refined[sz++] = b;
			}
			fs->WriteBytes(refined, sz);
		}

		void RDXObjectManager::SerializeTextString(const String *str, IO::IFileStream *fs) const
		{
			if(!str)
			{
				fs->WriteBytes(" null", 5);
				return;
			}
			
			fs->WriteBytes(" \'", 2);

			LargeInt nChars = str->Length();

			const LargeInt backlogSize = STRING_ENCODE_BACKLOG_SIZE;
			const LargeInt backlogLimit = STRING_ENCODE_BACKLOG_SIZE - 5;
			UInt8 backlog[backlogSize];
			LargeInt backlogOffset = 0;

			for(LargeInt i=0;i<nChars;i++)
			{
				backlogOffset += EncodeUTF8Char(str->AsChars()[i], backlog + backlogOffset);
				if(backlogOffset >= backlogLimit)
				{
					WriteEncodedStringBytes(fs, backlog, backlogOffset);
					backlogOffset = 0;
				}
			}

			if(backlogOffset)
				WriteEncodedStringBytes(fs, backlog, backlogOffset);
			fs->WriteBytes("\'", 1);
		}

		void RDXObjectManager::StringSerializer::SerializeBinaryInstance(IObjectManager *objm, const void *obj, IO::IFileStream *fs, const ObjectManagement::SSIDTable *ssidTable) const
		{
		}

		void RDXObjectManager::StringSerializer::SerializeTextInstance(IObjectManager *objm, const void *obj, IO::IFileStream *fs, const ObjectManagement::SSIDTable *ssidTable) const
		{
		}

		void RDXObjectManager::MethodProcessor::MarkDependencies(IObjectManager *objm, void *obj, const StructuredType *st,
			bool markNative, ISerializer *ser, ScanID scanID, GCLink gcl) const
		{
			const Method *m = static_cast<const Method*>(obj);
			if(markNative)
			{
				objm->SerializeIncludeObject(ser, m->_native.ilinstructions, gcl);
				objm->SerializeIncludeObject(ser, m->_native.ilResumeFlags, gcl);
				objm->SerializeIncludeObject(ser, m->_native.compactArgs, gcl);
				objm->SerializeIncludeObject(ser, m->_native.largeArgs, gcl);
				objm->SerializeIncludeObject(ser, m->_native.callPoints, gcl);
				objm->SerializeIncludeObject(ser, m->_native.debugInfo, gcl);
				objm->SerializeIncludeObject(ser, m->_native.translation1, gcl);
				objm->SerializeIncludeObject(ser, m->_native.translation2, gcl);
				objm->SerializeIncludeObject(ser, m->_native.compactedJournals, gcl);
				objm->SerializeIncludeObject(ser, m->_native.exHandlers, gcl);
			}
		}

		void RDXObjectManager::MethodProcessor::Finalize(void *obj, IObjectManager *objm) const
		{
			Method *m = static_cast<Method*>(obj);
			if(m->_native.nativeInstructions)
				objm->GetCodeProvider()->ReleaseExecutable(objm, m);
		}

		bool RDXObjectManager::MethodProcessor::OnLoad(OperationContext *ctx, void *obj, IObjectManager *objm) const
		{
			RDX_TRY(ctx)
			{
				Method *m = static_cast<Method*>(obj);
				if(!m->parameters)
					RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

				if(m->vftIndex)
				{
					// Make sure that this will call the expected method when invoked
					if(m->vftIndex < 0)
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
					if(m->parameters == NULL)
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

					if(m->thisParameterOffset <= 0 || m->thisParameterOffset > GCInfo::From(m->parameters)->numElements)
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

					// Determine "this" type
					const Type *thisType = m->parameters[m->thisParameterOffset - 1].type;
					if(thisType == NULL)
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
					if(GCInfo::From(thisType)->containerType != objm->GetBuiltIns()->st_StructuredType)
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

					// Verify that the type this will invoke will actually call this method
					const StructuredType *thisST = static_cast<const StructuredType *>(thisType);
					if(thisST->storageSpecifier != EnumValue::From(StructuredType::SS_Interface) &&
						thisST->storageSpecifier != EnumValue::From(StructuredType::SS_Class))
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

					if(thisST->virtualMethods == NULL)
						RDX_STHROW(ctx, Errors::RDX_ERROR_INCOMPATIBLE_VTABLE);
					if(m->vftIndex <= 0 || m->vftIndex > GCInfo::From(thisST->virtualMethods)->numElements)
						RDX_STHROW(ctx, Errors::RDX_ERROR_INCOMPATIBLE_VTABLE);
					if(thisST->virtualMethods[m->vftIndex - 1] != m)
						RDX_STHROW(ctx, Errors::RDX_ERROR_INCOMPATIBLE_VTABLE);
				}

				// Validate that the parameters are valid
				LargeInt numParameters = GCInfo::From(m->parameters)->numElements;
				for(LargeInt i=0;i<numParameters;i++)
				{
					const MethodParameter *param = m->parameters + i;
					// IsNotNull is only valid for reference types
					if(param->isNotNull && !objm->TypeIsObjectReference(param->type))
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
				}

				NativeCallback ncb = m->_native.nativeCall;
				if(!ncb)
				{
					const String *gstSymbol = GCInfo::From(m)->gstSymbol;
					if(gstSymbol && m->bytecode == NULL)
					{
						const NativeCallback *icb = Intrinsics::LookupBuiltin(gstSymbol);
						if(icb)
							ncb = *icb;
						else
							ncb = objm->GetTypeHost()->HookMethod(gstSymbol);

						if(ncb)
						{
							m->_native.nativeCall = ncb;
							m->_native.isNativeCall = true;
						}
						else if(!m->isAbstract)
							RDX_STHROW(ctx, Errors::RDX_ERROR_NATIVE_METHOD_UNBOUND);
					}
					else
					{
						if(m->bytecode)
						{
							if(m->isAbstract)
								RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
						}
						else
							if(!m->isAbstract)
								RDX_STHROW(ctx, Errors::RDX_ERROR_NATIVE_METHOD_UNBOUND);
					}

					RDX_PROTECT(ctx, ILCompiler::CompileMethod(ctx, m, objm) );
				}

				return true;
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROWV(ctx, false);
			}
			RDX_ENDTRY
		}

		BuiltIns *RDXObjectManager::GetBuiltIns()
		{
			return &_builtins;
		}

		const BuiltIns *RDXObjectManager::GetBuiltIns() const
		{
			return &_builtins;
		}

		bool RDXObjectManager::MethodOverrideCompatible(const StructuredType *implementingType, const Method *base, const Method *ov)
		{
			if(ov == NULL || base == NULL)
				return false;	// NULLs are always invalid

			if(base == ov)
				return true;

			if(ov->isAbstract && !base->isAbstract)
				return false;	// Abstracts can't override valid methods

			LargeInt numOverrideRV = 0;
			if(ov->returnTypes)
				numOverrideRV = GCInfo::From(ov->returnTypes)->numElements;

			LargeInt numOverrideP = 0;
			if(ov->parameters)
				numOverrideP = GCInfo::From(ov->parameters)->numElements;

			LargeInt numBaseRV = 0;
			if(base->returnTypes)
				numBaseRV = GCInfo::From(base->returnTypes)->numElements;

			LargeInt numBaseP = 0;
			if(base->parameters)
				numBaseP = GCInfo::From(base->parameters)->numElements;

			if(numOverrideRV != numBaseRV || numOverrideP != numBaseP)
				return false;

			for(LargeInt i=0;i<numBaseRV;i++)
			{
				// Bad method type def
				if(ov->returnTypes[i] == NULL || base->returnTypes[i] == NULL)
					return false;

				if(ov->returnTypes[i] != base->returnTypes[i])
					return false;
			}

			if(base->thisParameterOffset != ov->thisParameterOffset)
				return false;

			for(LargeInt i=0;i<numBaseP;i++)
			{
				// Bad method type def
				if(ov->parameters[i].type == NULL || base->parameters[i].type == NULL)
					return false;

				const GCInfo *plist = GCInfo::From(ov->parameters);

				if(i == (base->thisParameterOffset - 1))
				{
					if(!TypesCompatible(implementingType, ov->parameters[i].type))
						return false;
				}
				else
				{
					if(ov->parameters[i].type != base->parameters[i].type)
						return false;
				}
				if(ov->parameters[i].isConstant != base->parameters[i].isConstant)
					return false;
				if(ov->parameters[i].isNotNull != base->parameters[i].isNotNull)
					return false;
			}
			return true;
		}

		void RDXObjectManager::ValidateStructure(OperationContext *ctx, StructuredType *st)
		{
			RDX_TRY(ctx)
			{
				if(st->storageSpecifier == EnumValue::From(StructuredType::SS_Enum))
				{
					if(!st->enumerants)
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

					bool hasZero = false;
					LargeInt nEnumerants = GCInfo::From(st->enumerants)->numElements;
					for(LargeInt i=0;i<nEnumerants;i++)
					{
						if(st->enumerants[i].value == EnumValue::From(0))
						{
							hasZero = true;
							break;
						}
					}

					if(!hasZero)
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
				}

				if(st->parentClass)
				{
					// Only classes can have parents, the parent must be a class
					if(st->storageSpecifier != EnumValue::From(StructuredType::SS_Class))
						RDX_STHROW(ctx, Errors::RDX_ERROR_FORBIDDEN_CLASS_EXTENSION);
					if(st->parentClass->storageSpecifier != EnumValue::From(StructuredType::SS_Class))
						RDX_STHROW(ctx, Errors::RDX_ERROR_FORBIDDEN_CLASS_EXTENSION);
					if(st->parentClass->isFinal)
						RDX_STHROW(ctx, Errors::RDX_ERROR_FORBIDDEN_CLASS_EXTENSION);
					
					if(st->parentClass->isLocalized && !(GCInfo::From(st)->gcflags & GCInfo::GCOF_TransientDuplicate))
					{
						// Parent is localized, make sure this is in the same domain as its parent
						if(GCInfo::From(st)->domain != GCInfo::From(st->parentClass)->domain)
							RDX_STHROW(ctx, Errors::RDX_ERROR_FORBIDDEN_CLASS_EXTENSION);
					}
				}

				LargeInt numVirtualMethods = 0;
				LargeInt numProperties = 0;
				if(st->virtualMethods)
				{
					numVirtualMethods = GCInfo::From(st->virtualMethods)->numElements;
					LargeInt numParentVirtualMethods = 0;
					if(st->parentClass && st->parentClass->virtualMethods)
						numParentVirtualMethods = GCInfo::From(st->parentClass->virtualMethods)->numElements;

					if(numParentVirtualMethods > numVirtualMethods)
						RDX_STHROW(ctx, Errors::RDX_ERROR_INCOMPATIBLE_VTABLE);

					// Make sure that all VFT functions are valid
					for(LargeInt i=0;i<numVirtualMethods;i++)
					{
						const Method *vMethod = st->virtualMethods[i];
						if(vMethod == NULL || vMethod->parameters == NULL)
							RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

						LargeInt numParameters = GCInfo::From(vMethod->parameters)->numElements;
						if(vMethod->thisParameterOffset <= 0 || vMethod->thisParameterOffset > numParameters)
							RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

						if(vMethod->parameters[vMethod->thisParameterOffset - 1].type != st)
						{
							// "this" parameter isn't this type.  That's OK if this was inherited, otherwise the VTable is incompatible.
							if(st->parentClass == NULL || st->parentClass->virtualMethods == NULL || i >= numParentVirtualMethods || st->parentClass->virtualMethods[i] != vMethod)
								RDX_STHROW(ctx, Errors::RDX_ERROR_INCOMPATIBLE_VTABLE);
						}
						if(vMethod->parameters[vMethod->thisParameterOffset - 1].isNotNull == FalseValue ||
							vMethod->parameters[vMethod->thisParameterOffset - 1].isConstant == FalseValue)
							RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
					}

					// Make sure that all overrides are compatible
					for(LargeInt i=0;i<numParentVirtualMethods;i++)
					{
						const Method *pMethod = st->parentClass->virtualMethods[i];
						const Method *vMethod = st->virtualMethods[i];

						if(!pMethod || !vMethod)
							RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

						if(!MethodOverrideCompatible(st, pMethod, vMethod))
							RDX_STHROW(ctx, Errors::RDX_ERROR_INCOMPATIBLE_VTABLE);

						if(vMethod->isAbstract && !st->isAbstract)
							RDX_STHROW(ctx, Errors::RDX_ERROR_INCOMPATIBLE_VTABLE);
					}
				}

				if(st->properties)
				{
					numProperties = GCInfo::From(st->properties)->numElements;

					if(st->parentClass)
					{
						LargeInt numParentProperties = 0;
						if(st->parentClass->properties)
							numParentProperties = GCInfo::From(st->parentClass->properties)->numElements;

						if(numParentProperties > numProperties)
							RDX_STHROW(ctx, Errors::RDX_ERROR_INCOMPATIBLE_PROPERTIES);

						const Property *props1 = st->properties;
						const Property *props2 = st->parentClass->properties;
						for(LargeInt i=0;i<numParentProperties;i++)
						{
							if(props1[i].type != props2[i].type ||
								props1[i].mustBeConstant != props2[i].mustBeConstant ||
								props1[i].isConstant != props2[i].isConstant)
								RDX_STHROW(ctx, Errors::RDX_ERROR_INCOMPATIBLE_PROPERTIES);
						}
					}
				}

				if(st->interfaces)
				{
					if(RefIsShell(st->interfaces))
						RDX_STHROW(ctx, Errors::RDX_ERROR_UNRESOLVED_SYMBOL_REFERENCE);

					LargeInt numInterfaces = GCInfo::From(st->interfaces)->numElements;
					LargeInt numParentInterfaces = 0;
					if(st->parentClass)
					{
						if(st->parentClass->interfaces)
							numParentInterfaces = GCInfo::From(st->parentClass->interfaces)->numElements;

						if(numParentInterfaces > numInterfaces)
							RDX_STHROW(ctx, Errors::RDX_ERROR_INCOMPATIBLE_VTABLE);

						for(LargeInt i=0;i<numParentInterfaces;i++)
							if(st->interfaces[i].type != st->parentClass->interfaces[i].type ||
								st->interfaces[i].vftOffset != st->parentClass->interfaces[i].vftOffset)
									RDX_STHROW(ctx, Errors::RDX_ERROR_INCOMPATIBLE_VTABLE);


					}

					// Can start later in the list since the first are identical and the vtable match can take care of those
					for(LargeInt i=numParentInterfaces;i<numInterfaces;i++)
					{
						const InterfaceImplementation* impl = st->interfaces + i;
						if(impl->type == NULL)
							RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
						if(RefIsShell(impl->type))
							RDX_STHROW(ctx, Errors::RDX_ERROR_UNRESOLVED_SYMBOL_REFERENCE);

						const StructuredType *ist = impl->type;
						LargeInt numIVT = 0;
						if(ist->virtualMethods)
							numIVT = GCInfo::From(ist->virtualMethods)->numElements;

						if(ist->storageSpecifier != EnumValue::From(StructuredType::SS_Interface))
							RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

						// Make sure the VTable set is in range
						if(impl->vftOffset < 0 || numIVT > numVirtualMethods || (numVirtualMethods - numIVT) < impl->vftOffset)
							RDX_STHROW(ctx, Errors::RDX_ERROR_INCOMPATIBLE_VTABLE);

						for(LargeInt ivti=0;ivti<numIVT;ivti++)
						{
							const Method *iMethod = ist->virtualMethods[ivti];
							const Method *vMethod = st->virtualMethods[impl->vftOffset + ivti];

							if(!iMethod)
								RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

							if(!MethodOverrideCompatible(st, iMethod, vMethod))
								RDX_STHROW(ctx, Errors::RDX_ERROR_INCOMPATIBLE_VTABLE);
						}
					}
				}
				else
				{
					// No interfaces, make sure the parent has none either
					if(st->parentClass && st->interfaces)
						RDX_STHROW(ctx, Errors::RDX_ERROR_INCOMPATIBLE_VTABLE);
				}
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROW(ctx);
			}
			RDX_ENDTRY
		}


		// It's possible for references to still be shells since this is called when only critical symbols are guaranteed to
		// be resolved.
		bool RDXObjectManager::ResolveStructure(OperationContext *ctx, StructuredType *st)
		{
			bool structureIsMutable = false;
			GCInfo *sti = GCInfo::From(st);

			RDX_TRY(ctx)
			{
				bool zeroFill = true;	// True if the structure is zero-fill
				bool bulk = true;		// True if the structure can be bulk serialized

				if(st->storageSpecifier == EnumValue::From(StructuredType::SS_Enum))
				{
					if(st->properties || st->defaultValue)
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

					st->_native.size = sizeof(EnumValue);
					st->_native.alignment = ALIGN_EnumValue;
					st->_native.flags |= (StructuredType::NativeProperties::STF_StructureEvaluated | StructuredType::NativeProperties::STF_ZeroFill);
#ifndef RDX_VALIDATE_DESERIALIZED_ENUMS
					st->_native.flags |= (StructuredType::NativeProperties::STF_AllowBulkSerialize);
#endif
					return true;
				}

				if(_nth)
					_nth->SetTypeProperties(this, st);

				LargeInt currentSize = 0;
				LargeInt currentAlignment = 0;
				LargeInt numContainedReferences = 0;
				LargeInt numParentProperties = 0;
				LargeInt numParentContainedReferences = 0;
				LargeInt parentSize = 0;
				LargeInt parentAlignment = 0;
				LargeInt nProperties = 0;
				if(st->properties)
					nProperties = GCInfo::From(st->properties)->numElements;

				if(st->parentClass)
				{
					if(RefIsShell(st->parentClass))
					{
						Package::ManifestLocal *ref = reinterpret_cast<Package::ManifestLocal*>(GCInfo::From(st->parentClass));
						RDX_STHROW(ctx, Errors::RDX_ERROR_UNRESOLVED_SYMBOL_REFERENCE);
					}

					if(!(st->parentClass->_native.flags & StructuredType::NativeProperties::STF_StructureEvaluated))
						return false;	// Parent isn't loaded, defer

					// NOTE: This also handles the pad-out of the base class
					currentSize = st->parentClass->_native.size;

					if(st->parentClass->_native.user.nativeSize == 0 &&
						(st->parentClass->properties == NULL || GCInfo::From(st->parentClass->properties)->numElements == 0))
						currentSize = 0;		// Parent is an empty class, so actual start offset is zero
					currentAlignment = st->parentClass->_native.alignment;

					if(!(st->parentClass->_native.flags & StructuredType::NativeProperties::STF_ZeroFill))
						zeroFill = false;
					if(!(st->parentClass->_native.flags & StructuredType::NativeProperties::STF_AllowBulkSerialize))
						bulk = false;
					if(st->_native.flags & StructuredType::NativeProperties::STF_StructureIsMutable)
						structureIsMutable = true;

					numParentProperties = 0;
					if(st->parentClass->_native.propertyOffsets)
						numParentProperties = GCInfo::From(st->parentClass->_native.propertyOffsets)->numElements;
					if(numParentProperties > nProperties)
						RDX_STHROW(ctx, Errors::RDX_ERROR_INCOMPATIBLE_PROPERTIES);

					if(!st->_native.user.typeProcessor)
						st->_native.user.typeProcessor = st->parentClass->_native.user.typeProcessor;
					if(!st->_native.user.typeSerializer)
						st->_native.user.typeSerializer = st->parentClass->_native.user.typeSerializer;

					numParentContainedReferences = numContainedReferences = st->parentClass->_native.numContainedReferences;
				}

				if(st->_native.user.nativeSize)
				{
					bool overflowed;
					// Align the native properties structure
					LargeInt nativeAlign = st->_native.user.nativeAlignment;
					
#ifndef RDX_ENABLE_PADDED_BULK_SERIALIZE
					LargeInt oldCurrentSize = currentSize;
#endif

					currentSize = PaddedSize(currentSize, nativeAlign, overflowed);
					if(overflowed)
						RDX_STHROW(ctx, Errors::RDX_ERROR_INTEGER_OVERFLOW);

#ifndef RDX_ENABLE_PADDED_BULK_SERIALIZE
					if(currentSize != oldCurrentSize)
						bulk = false;
#endif
					if(currentAlignment < nativeAlign)
						currentAlignment = nativeAlign;
					if(!CheckAddOverflow(currentSize, st->_native.user.nativeSize))
						RDX_STHROW(ctx, Errors::RDX_ERROR_INTEGER_OVERFLOW);
					currentSize += st->_native.user.nativeSize;

					if(!(st->_native.user.flags & StructuredType::NativeProperties::UserProperties::STUF_NativeSafeToSerialize))
						bulk = false;

					// Fall-through will handle final padding
				}
				
				if(st->properties)
				{
					if(st->storageSpecifier != EnumValue::From(StructuredType::SS_Class) &&
						st->storageSpecifier != EnumValue::From(StructuredType::SS_ValStruct) &&
						st->storageSpecifier != EnumValue::From(StructuredType::SS_RefStruct))
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

					if(RefIsShell(st->properties))
						RDX_STHROW(ctx, Errors::RDX_ERROR_UNRESOLVED_SYMBOL_REFERENCE);

					RDX_PROTECT_ASSIGN(ctx, st->_native.propertyOffsets, Create1DArray<LargeInt>(ctx, nProperties) );

					// Copy the parent properties
					for(LargeInt i=0;i<numParentProperties;i++)
						st->_native.propertyOffsets[i] = st->parentClass->_native.propertyOffsets[i];

					for(LargeInt i=numParentProperties;i<nProperties;i++)
					{
						bool isRef = false;

						LargeInt pSize = 0;
						LargeInt pAlignment = 1;
						Type *pType = st->properties[i].type;

						if(!st->properties[i].isConstant)
							structureIsMutable = true;

						if(!pType)
							RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
						if(RefIsShell(pType))
							RDX_STHROW(ctx, Errors::RDX_ERROR_UNRESOLVED_SYMBOL_REFERENCE);
						if(pType == _builtins.st_Varying)
							RDX_STHROW(ctx, Errors::RDX_ERROR_FORBIDDEN_VARYING_USAGE);

						GCInfo *stpi = GCInfo::From(pType);

						const Type *pTypeType = GCInfo::From(pType)->containerType;
						const GCInfo *pTypeI = GCInfo::From(pTypeType);
						if(pTypeType == _builtins.st_StructuredType)
						{
							StructuredType *pst = static_cast<StructuredType*>(pType);
							switch(pst->storageSpecifier.Value())
							{
							case StructuredType::SS_Interface:
							case StructuredType::SS_Class:
								isRef = true;
								break;
							case StructuredType::SS_Enum:
								pSize = sizeof(EnumValue);
								pAlignment = ALIGN_EnumValue;
								break;
							case StructuredType::SS_ValStruct:
							case StructuredType::SS_RefStruct:
								// Make sure this has been evaluated
								if(!(pst->_native.flags & StructuredType::NativeProperties::STF_StructureEvaluated))
									return false;

								numContainedReferences += pst->_native.numContainedReferences;

								pSize = pst->_native.size;
								pAlignment = pst->_native.alignment;

								if(!(pst->_native.flags & StructuredType::NativeProperties::STF_AllowBulkSerialize))
									bulk = false;
								break;
							}
						}
						else if(pTypeType == _builtins.st_ArrayOfType)
							isRef = true;
						else if(pTypeType == _builtins.st_DelegateType)
							isRef = true;
						else
							RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

						if(isRef)
						{
							pSize = sizeof(void*);
							pAlignment = RDX_ALIGN_POINTER;
							numContainedReferences++;
						}

						if(pAlignment > currentAlignment)
							currentAlignment = pAlignment;

						// Align
						LargeInt slippage = currentSize % pAlignment;
						LargeInt padding = 0;
						if(slippage)
							padding = pAlignment - slippage;
#ifndef RDX_ENABLE_PADDED_BULK_SERIALIZE
						if(padding != 0)
							bulk = false;
#endif
						currentSize += padding;

						st->_native.propertyOffsets[i] = currentSize;

						if(!CheckAddOverflow(currentSize, pSize))
							RDX_STHROW(ctx, Errors::RDX_ERROR_INTEGER_OVERFLOW);

						currentSize += pSize;
					}
				}

				if(currentAlignment == 0)
					currentAlignment = 1;
				if(currentSize == 0)
					currentSize = 1;

				// Pad to struct size
				{
					LargeInt slippage = currentSize % currentAlignment;
					LargeInt padding = 0;
					if(slippage)
						padding = currentAlignment - slippage;
#ifndef RDX_ENABLE_PADDED_BULK_SERIALIZE
					if(padding != 0)
						bulk = false;
#endif

					if(!CheckAddOverflow(currentSize, padding))
						RDX_STHROW(ctx, Errors::RDX_ERROR_INTEGER_OVERFLOW);

					currentSize += padding;
				}

				// Map out references
				if(numContainedReferences)
				{
					bulk = false;


					RDX_PROTECT_ASSIGN(ctx, st->_native.containedReferences,
						Create1DArray<StructuredType::NativeProperties::ContainedReference>(ctx, numContainedReferences) );

					StructuredType::NativeProperties::ContainedReference *refs = st->_native.containedReferences;

					// Copy parent contained references
					for(LargeInt i=0;i<numParentContainedReferences;i++)
						*refs++ = st->parentClass->_native.containedReferences[i];
					
					for(LargeInt i=numParentProperties;i<nProperties;i++)
					{
						LargeInt pOffset = st->_native.propertyOffsets[i];

						bool isRef = false;
						Type *pType = st->properties[i].type;

						const Type *pTypeType = GCInfo::From(pType)->containerType;
						if(pTypeType == _builtins.st_StructuredType)
						{
							StructuredType *pst = static_cast<StructuredType*>(pType);
							switch(pst->storageSpecifier.Value())
							{
							case StructuredType::SS_Interface:
							case StructuredType::SS_Class:
								isRef = true;
								break;
							case StructuredType::SS_Enum:
								break;
							case StructuredType::SS_ValStruct:
							case StructuredType::SS_RefStruct:
								{
									LargeInt nxRefs = pst->_native.numContainedReferences;
									if(nxRefs)
									{
										const StructuredType::NativeProperties::ContainedReference *xrefs = pst->_native.containedReferences;
										for(LargeInt xi=0;xi<nxRefs;xi++)
										{
											StructuredType::NativeProperties::ContainedReference cr;
											cr = xrefs[xi];
											cr.offset = xrefs[xi].offset + pOffset;
											*refs++ = cr;
										}
									}
								}
								break;
							}
						}
						else if(pTypeType == _builtins.st_DelegateType)
							isRef = true;
						else if(pTypeType == _builtins.st_ArrayOfType)
							isRef = true;
						else
							RDX_STHROW(ctx, Errors::RDX_ERROR_INTERNAL_DESYNCED_COUNTER);

						if(isRef)
						{
							StructuredType::NativeProperties::ContainedReference cr;
							cr.requiredType = pType;
							cr.offset = pOffset;
							cr.mustBeConstant = (st->properties[i].mustBeConstant != FalseValue);
							*refs++ = cr;
						}
					}
				}

				if(zeroFill && !st->defaultValue)
				{
					st->_native.actualDefaultValue = NULL;
					st->_native.flags |=	(StructuredType::NativeProperties::STF_ZeroFill |
					StructuredType::NativeProperties::STF_DependencyDefaultsEvaluated | 
					StructuredType::NativeProperties::STF_DefaultEvaluated);
				}

				if(bulk)
					st->_native.flags |= StructuredType::NativeProperties::STF_AllowBulkSerialize;

				// Done
				st->_native.numContainedReferences = numContainedReferences;
				st->_native.size = currentSize;
				st->_native.alignment = currentAlignment;
				st->_native.flags |= StructuredType::NativeProperties::STF_StructureEvaluated;

				if(structureIsMutable)
					st->_native.flags |= StructuredType::NativeProperties::STF_StructureIsMutable;
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROWV(ctx, false);
			}
			RDX_ENDTRY

			return true;
		}

#define INITIALIZE_AOT_NAMED(t, n)	\
	RDX_PROTECT(ctx, InitializeAOT(ctx, _builtins.aot_##t, "#Core." n "[C]", _builtins.st_##t) )
		
#define INITIALIZE_AOT(t)	\
	INITIALIZE_AOT_NAMED(t, "RDX." #t)
		
#define INITIALIZE_AOT_CRITICAL(t)	\
	INITIALIZE_AOT(t);	\
	GCInfo::From(_builtins.aot_##t)->gcflags |= GCInfo::GCOF_Critical

#define INITIALIZE_PROPERTY(propArray, index, propName, propType)	\
	RDX_PROTECT_ASSIGN(ctx, _builtins.propArray[index].name, CreateStringASCII(ctx, propName) );\
	_builtins.propArray[index].type = _builtins.propType;\
	_builtins.propArray[index].isConstant = TrueValue;\
	if(GCInfo::From(_builtins.propType)->containerType == _builtins.st_ArrayOfType)\
		_builtins.propArray[index].mustBeConstant = TrueValue\

		void RDXObjectManager::InitializeAOT(OperationContext *ctx, CRef<ArrayOfType> &aotRef, const char *name, CRef<StructuredType> &subtypeRef)
		{
			RDX_TRY(ctx)
			{
				 
				GCInfo *gci = GCInfo::From(aotRef);
				GCInfo::From(aotRef)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				aotRef->numDimensions = 1;
				aotRef->type = subtypeRef;
				aotRef->isConstant = TrueValue;
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, name), aotRef) );
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROW(ctx);
			}
			RDX_ENDTRY
		}

		void RDXObjectManager::InitializeBuiltInTypes(OperationContext *ctx)
		{
			RDX_TRY(ctx)
			{
				this->_initialized = false;

				String *str = NULL;

				RDX_PROTECT_ASSIGN(ctx, _builtins.st_StructuredType, CreateObject<StructuredType>(ctx) );
				GCInfo::From(_builtins.st_StructuredType)->containerType =
					GCInfo::From(_builtins.st_StructuredType)->contentsType = _builtins.st_StructuredType;
				GCInfo::From(_builtins.st_StructuredType)->containedStructure = _builtins.st_StructuredType;
				GCInfo::From(_builtins.st_StructuredType)->gcflags = GCInfo::GCOF_Duplicable | GCInfo::GCOF_Critical;
				GCInfo::From(_builtins.st_StructuredType)->domain = DOMAIN_Core;
				_builtins.st_StructuredType->_native.user.nativeSize = sizeof(StructuredType::NativeProperties);
				_builtins.st_StructuredType->_native.user.nativeAlignment = RDX_ALIGNOF(StructuredType::NativeProperties);
				_builtins.st_StructuredType->_native.user.flags |=
					StructuredType::NativeProperties::UserProperties::STUF_NativeChangesDuringLoad |
					StructuredType::NativeProperties::UserProperties::STUF_AllowDuplicates;
				_builtins.st_StructuredType->isFinal = true;
				GCInfo::From(_builtins.st_StructuredType)->typeProcessor =
					_builtins.st_StructuredType->_native.user.typeProcessor = &StructuredTypeProcessor::instance;

				RDX_PROTECT_ASSIGN(ctx, _builtins.st_ArrayOfType, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_DelegateType, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );

				RDX_PROTECT_ASSIGN(ctx, _builtins.st_String, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );

				RDX_PROTECT_ASSIGN(ctx, _builtins.st_Object, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_Array, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_Type, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_Bool, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_Varying, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_LargeInt, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_Int, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_Byte, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_Char, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_Property, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_MethodParameter, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_Enumerant, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_StorageSpecifier, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_Method, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_Thread, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_InstructionFileInfo, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_InterfaceImplementation, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.st_MutableObjectRef, CreateObject<StructuredType>(ctx, _builtins.st_StructuredType, NULL, DOMAIN_Core) );

				RDX_PROTECT_ASSIGN(ctx, _builtins.aot_InterfaceImplementation, CreateObject<ArrayOfType>(ctx, _builtins.st_ArrayOfType, NULL, DOMAIN_Duplicable) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.aot_Instruction, CreateObject<ArrayOfType>(ctx, _builtins.st_ArrayOfType, NULL, DOMAIN_Duplicable) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.aot_StructuredType, CreateObject<ArrayOfType>(ctx, _builtins.st_ArrayOfType, NULL, DOMAIN_Duplicable) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.aot_Type, CreateObject<ArrayOfType>(ctx, _builtins.st_ArrayOfType, NULL, DOMAIN_Duplicable) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.aot_Enumerant, CreateObject<ArrayOfType>(ctx, _builtins.st_ArrayOfType, NULL, DOMAIN_Duplicable) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.aot_MethodParameter, CreateObject<ArrayOfType>(ctx, _builtins.st_ArrayOfType, NULL, DOMAIN_Duplicable) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.aot_Property, CreateObject<ArrayOfType>(ctx, _builtins.st_ArrayOfType, NULL, DOMAIN_Duplicable) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.aot_Method, CreateObject<ArrayOfType>(ctx, _builtins.st_ArrayOfType, NULL, DOMAIN_Duplicable) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.aot_String, CreateObject<ArrayOfType>(ctx, _builtins.st_ArrayOfType, NULL, DOMAIN_Duplicable) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.aot_Int, CreateObject<ArrayOfType>(ctx, _builtins.st_ArrayOfType, NULL, DOMAIN_Duplicable) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.aot_Char, CreateObject<ArrayOfType>(ctx, _builtins.st_ArrayOfType, NULL, DOMAIN_Duplicable) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.aot_Byte, CreateObject<ArrayOfType>(ctx, _builtins.st_ArrayOfType, NULL, DOMAIN_Duplicable) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.aot_Object, CreateObject<ArrayOfType>(ctx, _builtins.st_ArrayOfType, NULL, DOMAIN_Duplicable) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.aot_InstructionFileInfo, CreateObject<ArrayOfType>(ctx, _builtins.st_ArrayOfType, NULL, DOMAIN_Duplicable) );
				
				// String needs to be set up immediately so StringProcessor is properly assigned for all future strings
				GCInfo::From(_builtins.st_String)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_String->parentClass = _builtins.st_Object;
				_builtins.st_String->storageSpecifier = EnumValue::From(StructuredType::SS_Class);
				_builtins.st_String->_native.user.typeProcessor = &StringProcessor::instance;
				_builtins.st_String->_native.user.typeSerializer = &StringSerializer::instance;
				_builtins.st_String->_native.user.flags |= StructuredType::NativeProperties::UserProperties::STUF_SerializeAsReference;
				_builtins.st_String->isFinal = TrueValue;

				// Its dependent char types need to be set up as well so that new strings have the correct type for the char array
				GCInfo::From(_builtins.st_Char)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_Char->storageSpecifier = EnumValue::From(StructuredType::SS_ValStruct);
				_builtins.st_Char->_native.user.nativeSize = sizeof(Char);
				_builtins.st_Char->_native.user.nativeAlignment = ALIGN_Char;
				_builtins.st_Char->_native.user.typeSerializer = &i_CharSerializer;
				_builtins.st_Char->_native.user.flags |= StructuredType::NativeProperties::UserProperties::STUF_NativeSafeToSerialize;
				
				GCInfo::From(_builtins.aot_Char)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.aot_Char->numDimensions = 1;
				_builtins.aot_Char->type = _builtins.st_Char;
				_builtins.aot_Char->isConstant = TrueValue;

				// Set this as the char array type for the string table
				_stringTable._aot_ConstChar = _builtins.aot_Char;

				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "#Core.char[C]"), _builtins.aot_Char) );
				
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.char"), _builtins.st_Char) );
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.int"), _builtins.st_Int) );
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.string"), _builtins.st_String) );

				// Set values
				GCInfo::From(_builtins.st_Object)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_Object->storageSpecifier = EnumValue::From(StructuredType::SS_Class);
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.Object"), _builtins.st_Object) );


				GCInfo::From(_builtins.st_Array)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_Array->storageSpecifier = EnumValue::From(StructuredType::SS_Class);
				_builtins.st_Array->parentClass = _builtins.st_Object;
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.Array"), _builtins.st_Array) );

				GCInfo::From(_builtins.st_ArrayOfType)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable | GCInfo::GCOF_Critical;
				_builtins.st_ArrayOfType->storageSpecifier = EnumValue::From(StructuredType::SS_Class);
				_builtins.st_ArrayOfType->parentClass = _builtins.st_Type;
				_builtins.st_ArrayOfType->isFinal = true;
				_builtins.st_ArrayOfType->_native.user.flags = StructuredType::NativeProperties::UserProperties::STUF_AllowDuplicates;
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.ArrayOfType"), _builtins.st_ArrayOfType) );

				GCInfo::From(_builtins.st_DelegateType)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable | GCInfo::GCOF_Critical;
				_builtins.st_DelegateType->storageSpecifier = EnumValue::From(StructuredType::SS_Class);
				_builtins.st_DelegateType->parentClass = _builtins.st_Type;
				_builtins.st_DelegateType->isFinal = true;
				_builtins.st_DelegateType->_native.user.flags = StructuredType::NativeProperties::UserProperties::STUF_AllowDuplicates;
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.DelegateType"), _builtins.st_DelegateType) );

				GCInfo::From(_builtins.st_Enumerant)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_Enumerant->storageSpecifier = EnumValue::From(StructuredType::SS_RefStruct);
				_builtins.st_Enumerant->_native.user.flags = StructuredType::NativeProperties::UserProperties::STUF_AllowDuplicates;
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.Enumerant"), _builtins.st_Enumerant) );

				GCInfo::From(_builtins.st_Type)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable | GCInfo::GCOF_Critical;
				_builtins.st_Type->parentClass = _builtins.st_Object;
				_builtins.st_Type->storageSpecifier = EnumValue::From(StructuredType::SS_Class);
				_builtins.st_Type->isAbstract = TrueValue;
				_builtins.st_Type->isLocalized = TrueValue;
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.Type"), _builtins.st_Type) );

				GCInfo::From(_builtins.st_Bool)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_Bool->storageSpecifier = EnumValue::From(StructuredType::SS_ValStruct);
				_builtins.st_Bool->_native.user.nativeSize = sizeof(Bool);
				_builtins.st_Bool->_native.user.nativeAlignment = ALIGN_Bool;
				_builtins.st_Bool->_native.user.typeSerializer = &BoolSerializer::instance;
				_builtins.st_Bool->_native.user.flags |= StructuredType::NativeProperties::UserProperties::STUF_NativeSafeToSerialize;
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.bool"), _builtins.st_Bool) );

				GCInfo::From(_builtins.st_Varying)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_Varying->storageSpecifier = EnumValue::From(StructuredType::SS_ValStruct);
				_builtins.st_Varying->_native.user.nativeSize = sizeof(TypedRuntimePointer);
				_builtins.st_Varying->_native.user.nativeAlignment = ALIGN_TypedRuntimePointer;
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.varying"), _builtins.st_Varying) );

				GCInfo::From(_builtins.st_LargeInt)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_LargeInt->storageSpecifier = EnumValue::From(StructuredType::SS_ValStruct);
				_builtins.st_LargeInt->_native.user.nativeSize = sizeof(LargeInt);
				_builtins.st_LargeInt->_native.user.nativeAlignment = ALIGN_LargeInt;
				_builtins.st_LargeInt->_native.user.typeSerializer = &i_LargeIntSerializer;
#ifdef RDX_ENABLE_LARGEINT_BULK_SERIALIZE
				_builtins.st_LargeInt->_native.user.flags |= StructuredType::NativeProperties::UserProperties::STUF_NativeSafeToSerialize;
#endif
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.largeint"), _builtins.st_LargeInt) );

				GCInfo::From(_builtins.st_Int)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_Int->storageSpecifier = EnumValue::From(StructuredType::SS_ValStruct);
				_builtins.st_Int->_native.user.nativeSize = sizeof(Int);
				_builtins.st_Int->_native.user.nativeAlignment = ALIGN_Int;
				_builtins.st_Int->_native.user.typeSerializer = &i_IntSerializer;
				_builtins.st_Int->_native.user.flags |= StructuredType::NativeProperties::UserProperties::STUF_NativeSafeToSerialize;
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.int"), _builtins.st_Int) );

				GCInfo::From(_builtins.st_Byte)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_Byte->storageSpecifier = EnumValue::From(StructuredType::SS_ValStruct);
				_builtins.st_Byte->_native.user.nativeSize = sizeof(Byte);
				_builtins.st_Byte->_native.user.nativeAlignment = ALIGN_Byte;
				_builtins.st_Byte->_native.user.typeSerializer = &i_ByteSerializer;
				_builtins.st_Byte->_native.user.flags |= StructuredType::NativeProperties::UserProperties::STUF_NativeSafeToSerialize;
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.byte"), _builtins.st_Byte) );

				GCInfo::From(_builtins.st_InstructionFileInfo)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_InstructionFileInfo->storageSpecifier = EnumValue::From(StructuredType::SS_RefStruct);
				_builtins.st_InstructionFileInfo->_native.user.flags = StructuredType::NativeProperties::UserProperties::STUF_AllowDuplicates;
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.InstructionFileInfo"), _builtins.st_InstructionFileInfo) );
				
				GCInfo::From(_builtins.st_Thread)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_Thread->storageSpecifier = EnumValue::From(StructuredType::SS_Class);
				_builtins.st_Thread->parentClass = _builtins.st_Object;
				_builtins.st_Thread->_native.user.typeProcessor = &ThreadProcessor::instance;
				_builtins.st_Thread->_native.user.typeSerializer = &ThreadSerializer::instance;
				_builtins.st_Thread->_native.user.nativeSize = sizeof(RuntimeThread);
				_builtins.st_Thread->_native.user.nativeAlignment = sizeof(void*);
				_builtins.st_Thread->isFinal = TrueValue;
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.Thread"), _builtins.st_Thread) );

				GCInfo::From(_builtins.st_Method)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_Method->storageSpecifier = EnumValue::From(StructuredType::SS_Class);
				_builtins.st_Method->parentClass = _builtins.st_Object;
				_builtins.st_Method->isFinal = TrueValue;
				_builtins.st_Method->_native.user.typeProcessor = &MethodProcessor::instance;
				_builtins.st_Method->_native.user.nativeSize = Method::NativeSize();
				_builtins.st_Method->_native.user.nativeAlignment = Method::NativeAlignment();
				_builtins.st_Method->_native.user.flags = StructuredType::NativeProperties::UserProperties::STUF_AllowDuplicates;
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.Method"), _builtins.st_Method) );

				GCInfo::From(_builtins.st_InterfaceImplementation)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_InterfaceImplementation->storageSpecifier = EnumValue::From(StructuredType::SS_RefStruct);
				_builtins.st_InterfaceImplementation->_native.user.flags = StructuredType::NativeProperties::UserProperties::STUF_AllowDuplicates;
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.InterfaceImplementation"), _builtins.st_InterfaceImplementation) );
				
				GCInfo::From(_builtins.st_MutableObjectRef)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_MutableObjectRef->storageSpecifier = EnumValue::From(StructuredType::SS_ValStruct);
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.MutableObjectRef"), _builtins.st_MutableObjectRef) );

				GCInfo::From(_builtins.st_Property)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_Property->storageSpecifier = EnumValue::From(StructuredType::SS_RefStruct);
				_builtins.st_Property->_native.user.flags = StructuredType::NativeProperties::UserProperties::STUF_AllowDuplicates;
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.Property"), _builtins.st_Property) );

				GCInfo::From(_builtins.st_MethodParameter)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_MethodParameter->storageSpecifier = EnumValue::From(StructuredType::SS_RefStruct);
				_builtins.st_MethodParameter->_native.user.flags = StructuredType::NativeProperties::UserProperties::STUF_AllowDuplicates;
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.MethodParameter"), _builtins.st_MethodParameter) );
				

				INITIALIZE_AOT(InterfaceImplementation);
				INITIALIZE_AOT_CRITICAL(Enumerant);
				INITIALIZE_AOT(StructuredType);
				INITIALIZE_AOT(Type);
				INITIALIZE_AOT_CRITICAL(Property);
				INITIALIZE_AOT(Method);
				INITIALIZE_AOT_NAMED(String, "string");
				INITIALIZE_AOT_NAMED(Int, "int");
				INITIALIZE_AOT_NAMED(Byte, "byte");
				INITIALIZE_AOT_NAMED(Object, "Object");
				INITIALIZE_AOT(InstructionFileInfo);
				INITIALIZE_AOT_CRITICAL(MethodParameter);

				GCInfo::From(_builtins.st_StructuredType)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable | GCInfo::GCOF_Critical;
				_builtins.st_StructuredType->parentClass = _builtins.st_Type;
				_builtins.st_StructuredType->storageSpecifier = EnumValue::From(StructuredType::SS_Class);
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.StructuredType"), _builtins.st_StructuredType) );

				RDX_PROTECT_ASSIGN(ctx, _builtins.e_StorageSpecifierEnumerants, Create1DArray<Enumerant>(ctx, 5, _builtins.aot_Enumerant, NULL, DOMAIN_Core) );

				RDX_PROTECT_ASSIGN(ctx, _builtins.p_EnumerantProperties, Create1DArray<Property>(ctx, 2, _builtins.aot_Property, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.p_MethodParameterProperties, Create1DArray<Property>(ctx, 3, _builtins.aot_Property, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.p_PropertyProperties, Create1DArray<Property>(ctx, 4, _builtins.aot_Property, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.p_ArrayOfTypeProperties, Create1DArray<Property>(ctx, 3, _builtins.aot_Property, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.p_DelegateTypeProperties, Create1DArray<Property>(ctx, 2, _builtins.aot_Property, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.p_StructuredTypeProperties, Create1DArray<Property>(ctx, 10, _builtins.aot_Property, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.p_MethodProperties, Create1DArray<Property>(ctx, 9, _builtins.aot_Property, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.p_InstructionFileInfoProperties, Create1DArray<Property>(ctx, 3, _builtins.aot_Property, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.p_InterfaceImplementationProperties, Create1DArray<Property>(ctx, 2, _builtins.aot_Property, NULL, DOMAIN_Core) );
				RDX_PROTECT_ASSIGN(ctx, _builtins.p_MutableObjectRefProperties, Create1DArray<Property>(ctx, 1, _builtins.aot_Property, NULL, DOMAIN_Core) );

				GCInfo::From(_builtins.e_StorageSpecifierEnumerants)->gcflags |= GCInfo::GCOF_Duplicable;
				RDX_PROTECT_ASSIGN(ctx, _builtins.e_StorageSpecifierEnumerants[0].name, CreateStringASCII(ctx, "SS_Class") );
				_builtins.e_StorageSpecifierEnumerants[0].value = EnumValue::From(StructuredType::SS_Class);
				RDX_PROTECT_ASSIGN(ctx, _builtins.e_StorageSpecifierEnumerants[1].name, CreateStringASCII(ctx, "SS_RefStruct") );
				_builtins.e_StorageSpecifierEnumerants[1].value = EnumValue::From(StructuredType::SS_RefStruct);
				RDX_PROTECT_ASSIGN(ctx, _builtins.e_StorageSpecifierEnumerants[2].name, CreateStringASCII(ctx, "SS_ValStruct") );
				_builtins.e_StorageSpecifierEnumerants[2].value = EnumValue::From(StructuredType::SS_ValStruct);
				RDX_PROTECT_ASSIGN(ctx, _builtins.e_StorageSpecifierEnumerants[3].name, CreateStringASCII(ctx, "SS_Enum") );
				_builtins.e_StorageSpecifierEnumerants[3].value = EnumValue::From(StructuredType::SS_Enum);
				RDX_PROTECT_ASSIGN(ctx, _builtins.e_StorageSpecifierEnumerants[4].name, CreateStringASCII(ctx, "SS_Interface") );
				_builtins.e_StorageSpecifierEnumerants[4].value = EnumValue::From(StructuredType::SS_Interface);
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.StorageSpecifier/enumerants"), _builtins.e_StorageSpecifierEnumerants) );

				GCInfo::From(_builtins.st_StorageSpecifier)->gcflags |= GCInfo::GCOF_Core | GCInfo::GCOF_Duplicable;
				_builtins.st_StorageSpecifier->storageSpecifier = EnumValue::From(StructuredType::SS_Enum);
				_builtins.st_StorageSpecifier->virtualMethods = NULL;
				_builtins.st_StorageSpecifier->enumerants = _builtins.e_StorageSpecifierEnumerants;
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.StorageSpecifier"), _builtins.st_StorageSpecifier) );

				GCInfo::From(_builtins.p_ArrayOfTypeProperties)->gcflags |= GCInfo::GCOF_Duplicable;
				INITIALIZE_PROPERTY(p_ArrayOfTypeProperties, 0, "type", st_Type);
				INITIALIZE_PROPERTY(p_ArrayOfTypeProperties, 1, "numDimensions", st_Int);
				INITIALIZE_PROPERTY(p_ArrayOfTypeProperties, 2, "isConstant", st_Bool);
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.ArrayOfType/properties"), _builtins.p_ArrayOfTypeProperties) );

				GCInfo::From(_builtins.p_DelegateTypeProperties)->gcflags |= GCInfo::GCOF_Duplicable;
				INITIALIZE_PROPERTY(p_DelegateTypeProperties, 0, "parameters", aot_MethodParameter);
				INITIALIZE_PROPERTY(p_DelegateTypeProperties, 1, "returnTypes", aot_Type);
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.DelegateType/properties"), _builtins.p_DelegateTypeProperties) );

				GCInfo::From(_builtins.p_MethodParameterProperties)->gcflags |= GCInfo::GCOF_Duplicable;
				INITIALIZE_PROPERTY(p_MethodParameterProperties, 0, "type", st_Type);
				INITIALIZE_PROPERTY(p_MethodParameterProperties, 1, "isConstant", st_Bool);
				INITIALIZE_PROPERTY(p_MethodParameterProperties, 2, "isNotNull", st_Bool);
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.MethodParameter/properties"), _builtins.p_MethodParameterProperties) );

				GCInfo::From(_builtins.p_PropertyProperties)->gcflags |= GCInfo::GCOF_Duplicable;
				INITIALIZE_PROPERTY(p_PropertyProperties, 0, "name", st_String);
				INITIALIZE_PROPERTY(p_PropertyProperties, 1, "type", st_Type);
				INITIALIZE_PROPERTY(p_PropertyProperties, 2, "isConstant", st_Bool);
				INITIALIZE_PROPERTY(p_PropertyProperties, 3, "mustBeConstant", st_Bool);
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.Property/properties"), _builtins.p_PropertyProperties) );

				GCInfo::From(_builtins.p_InterfaceImplementationProperties)->gcflags |= GCInfo::GCOF_Duplicable;
				INITIALIZE_PROPERTY(p_InterfaceImplementationProperties, 0, "type", st_StructuredType);
				INITIALIZE_PROPERTY(p_InterfaceImplementationProperties, 1, "vftOffset", st_Int);
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.InterfaceImplementation/properties"), _builtins.p_InterfaceImplementationProperties) );

				GCInfo::From(_builtins.p_MutableObjectRefProperties)->gcflags |= GCInfo::GCOF_Duplicable;
				INITIALIZE_PROPERTY(p_MutableObjectRefProperties, 0, "value", st_Object);
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.MutableObjectRef/properties"), _builtins.p_MutableObjectRefProperties) );

				GCInfo::From(_builtins.p_InstructionFileInfoProperties)->gcflags |= GCInfo::GCOF_Duplicable;
				INITIALIZE_PROPERTY(p_InstructionFileInfoProperties, 0, "filename", st_String);
				INITIALIZE_PROPERTY(p_InstructionFileInfoProperties, 1, "line", st_Int);
				INITIALIZE_PROPERTY(p_InstructionFileInfoProperties, 2, "firstInstruction", st_Int);
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.InstructionFileInfo/properties"), _builtins.p_InstructionFileInfoProperties) );

				GCInfo::From(_builtins.p_MethodProperties)->gcflags |= GCInfo::GCOF_Duplicable;
				INITIALIZE_PROPERTY(p_MethodProperties, 0, "parameters", aot_MethodParameter);
				INITIALIZE_PROPERTY(p_MethodProperties, 1, "returnTypes", aot_Type);
				INITIALIZE_PROPERTY(p_MethodProperties, 2, "bytecode", aot_Byte);
				INITIALIZE_PROPERTY(p_MethodProperties, 3, "resArgs", aot_Object);
				INITIALIZE_PROPERTY(p_MethodProperties, 4, "instructionFileInfos", aot_InstructionFileInfo);
				INITIALIZE_PROPERTY(p_MethodProperties, 5, "numInstructions", st_Int);
				INITIALIZE_PROPERTY(p_MethodProperties, 6, "vftIndex", st_Int);
				INITIALIZE_PROPERTY(p_MethodProperties, 7, "thisParameterOffset", st_Int);
				INITIALIZE_PROPERTY(p_MethodProperties, 8, "isAbstract", st_Bool);
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.Method/properties"), _builtins.p_MethodProperties) );

				GCInfo::From(_builtins.p_EnumerantProperties)->gcflags |= GCInfo::GCOF_Duplicable;
				INITIALIZE_PROPERTY(p_EnumerantProperties, 0, "name", st_String);
				INITIALIZE_PROPERTY(p_EnumerantProperties, 1, "value", RDX_ENUM_INTERNAL_TYPE);
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.Enumerant/properties"), _builtins.p_EnumerantProperties) );

				GCInfo::From(_builtins.p_StructuredTypeProperties)->gcflags |= GCInfo::GCOF_Duplicable;
				INITIALIZE_PROPERTY(p_StructuredTypeProperties, 0, "parentClass", st_StructuredType);
				INITIALIZE_PROPERTY(p_StructuredTypeProperties, 1, "interfaces", aot_InterfaceImplementation);
				INITIALIZE_PROPERTY(p_StructuredTypeProperties, 2, "storageSpecifier", st_StorageSpecifier);
				INITIALIZE_PROPERTY(p_StructuredTypeProperties, 3, "virtualMethods", aot_Method);
				INITIALIZE_PROPERTY(p_StructuredTypeProperties, 4, "properties", aot_Property);
				INITIALIZE_PROPERTY(p_StructuredTypeProperties, 5, "enumerants", aot_Enumerant);
				INITIALIZE_PROPERTY(p_StructuredTypeProperties, 6, "defaultValue", st_Object);
				INITIALIZE_PROPERTY(p_StructuredTypeProperties, 7, "isFinal", st_Bool);
				INITIALIZE_PROPERTY(p_StructuredTypeProperties, 8, "isAbstract", st_Bool);
				INITIALIZE_PROPERTY(p_StructuredTypeProperties, 9, "isLocalized", st_Bool);
				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, CreateStringASCII(ctx, "Core.RDX.StructuredType/properties"), _builtins.p_StructuredTypeProperties) );

				// Assign enumerants and properties
				_builtins.st_StorageSpecifier->enumerants = _builtins.e_StorageSpecifierEnumerants;

				_builtins.st_Enumerant->properties = _builtins.p_EnumerantProperties;
				_builtins.st_MethodParameter->properties = _builtins.p_MethodParameterProperties;
				_builtins.st_Property->properties = _builtins.p_PropertyProperties;
				_builtins.st_ArrayOfType->properties = _builtins.p_ArrayOfTypeProperties;
				_builtins.st_DelegateType->properties = _builtins.p_DelegateTypeProperties;
				_builtins.st_StructuredType->properties = _builtins.p_StructuredTypeProperties;
				_builtins.st_Method->properties = _builtins.p_MethodProperties;
				_builtins.st_InstructionFileInfo->properties = _builtins.p_InstructionFileInfoProperties;
				_builtins.st_InterfaceImplementation->properties = _builtins.p_InterfaceImplementationProperties;
				_builtins.st_MutableObjectRef->properties = _builtins.p_MutableObjectRefProperties;

				// Resolve built-in structures
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_Object) );

				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_Type) );

				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_Bool) );
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_Varying) );
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_LargeInt) );
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_Int) );
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_Char) );
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_Byte) );
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_String) );
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_MethodParameter) );

				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_ArrayOfType) );
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_StructuredType) );
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_DelegateType) );

				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_Property) );
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_Enumerant) );
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_StorageSpecifier) );
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_Method) );
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_InstructionFileInfo) );
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_InterfaceImplementation) );
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_Thread) );
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_Array) );
				RDX_PROTECT(ctx, this->ResolveStructure(ctx, _builtins.st_MutableObjectRef) );

				this->_initialized = true;
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROW(ctx);
			}
			RDX_ENDTRY
		}

		// Returns what the size of a single element would be if created as an instance of the specified type.
		// For arrays, this is the size of an object reference.  For objects, this is the size of the contained structure.
		LargeInt RDXObjectManager::TypeElementSize(const Type *t)
		{
			if(t == NULL)
				return 0;

			const Type *subType;
			if(GCInfo::From(t)->containerType == _builtins.st_StructuredType)
				return static_cast<const StructuredType *>(t)->_native.size;
			else if(GCInfo::From(t)->containerType == _builtins.st_ArrayOfType)
			{
				subType = static_cast<const ArrayOfType*>(t)->type;

				if(GCInfo::From(subType)->containerType == _builtins.st_StructuredType)
				{
					const StructuredType *st = static_cast<const StructuredType*>(subType);
					switch(st->storageSpecifier.Value())
					{
					case StructuredType::SS_Enum:
						return sizeof(EnumValue);
					case StructuredType::SS_Class:
					case StructuredType::SS_Interface:
						return sizeof(void*);
						break;
					case StructuredType::SS_RefStruct:
					case StructuredType::SS_ValStruct:
						return st->_native.size;
						break;
					default:
						return 0;
					};
				}
				else if(GCInfo::From(subType)->containerType == _builtins.st_ArrayOfType)
				{
					return sizeof(void*);
				}
				else if(GCInfo::From(subType)->containerType == _builtins.st_DelegateType)
				{
					return sizeof(void*);
				}
				else
					return 0;
			}
			else	// Can't create delegates, or anything else
				return 0;
		}

		CRef<void> RDXObjectManager::CreateContainer(OperationContext *ctx, LargeInt elementSize, LargeInt numElements, Int numDimensions,
			Domain domain, const Type *t, const ITypeProcessor *tp, LargeInt overflow)
		{
			const Type *contentsType = NULL;
			const StructuredType *structureType = NULL;
			bool flagAsConst = false;
			Method **vft = NULL;

			if(t != NULL)
			{
				if(GCInfo::From(t)->containerType == _builtins.st_ArrayOfType)
				{
					const ArrayOfType *aot = static_cast<const ArrayOfType*>(t);
					contentsType = aot->type;

					if(GCInfo::From(contentsType)->containerType == _builtins.st_StructuredType)
					{
						const StructuredType *st = static_cast<const StructuredType*>(contentsType);
						switch(st->storageSpecifier.Value())
						{
						case StructuredType::SS_Enum:
						case StructuredType::SS_ValStruct:
						case StructuredType::SS_RefStruct:
							// Value types
							structureType = st;
							break;
						case StructuredType::SS_Class:
						case StructuredType::SS_Interface:
							// Reference types
							break;
						}
					}

					flagAsConst = (aot->isConstant != FalseValue);
				}
				else if(GCInfo::From(t)->containerType == _builtins.st_StructuredType)
				{
					contentsType = t;
					structureType = static_cast<const StructuredType*>(t);
					if(!tp)
						tp = structureType->_native.user.typeProcessor;
					vft = structureType->virtualMethods;

					if(structureType->isAbstract)
						RDX_LTHROWV(ctx, Errors::RDX_ERROR_CREATED_ABSTRACT_TYPE, NULL);
				}
			}

			LargeInt numPaddedElements;
			if(!CheckAddOverflow(numElements, overflow))
				RDX_LTHROWV(ctx, Errors::RDX_ERROR_ALLOCATION_FAILED, NULL);
			numPaddedElements = numElements + overflow;

			LargeInt sz = GCInfo::AllocationSize(numPaddedElements, elementSize, numDimensions);
			if(!sz)
				RDX_LTHROWV(ctx, Errors::RDX_ERROR_ALLOCATION_FAILED, NULL);

			bool collected = false;
			NonAtomicInt cycle = Threading::AtomicIncrement(&this->_gcCounter);

			if(cycle % this->_gcFrequency == 0 && _initialized)
			{
				collected = true;
				this->CollectGarbage(ctx);
			}

			LargeInt sentinelSize = 0;
#ifdef RDX_ENABLE_SENTINELS
			sentinelSize = sizeof(static_cast<const GCInfo *>(NULL)->sentinel1);
#endif

			GCInfo *gci = reinterpret_cast<GCInfo *>(_allocator.Realloc(NULL, sz + sentinelSize, RDX_MAX_ALIGNMENT));
			if(gci == NULL)
			{
				if(!_initialized)
					RDX_LTHROWV(ctx, Errors::RDX_ERROR_ALLOCATION_FAILED, NULL);

				// Failed allocation, try collecting garbage and allocating again
				if(!collected)
				{
					collected = true;
					this->CollectGarbage(ctx);
					gci = static_cast<GCInfo *>(_allocator.Realloc(NULL, sz + sentinelSize, RDX_MAX_ALIGNMENT));
				}
				if(gci == NULL)
					RDX_LTHROWV(ctx, Errors::RDX_ERROR_ALLOCATION_FAILED, NULL);
			}

			new (gci) GCInfo(this, t, contentsType, structureType, tp, numElements, elementSize, numDimensions);

			gci->domain = domain;
			gci->gcflags = 0;
			gci->vft = vft;
			gci->serializeScanID = 0;
			
#ifdef RDX_ENABLE_SENTINELS
			static UInt32 crudeSequentialID = 0;

			gci->sequentialID = crudeSequentialID++;
			gci->sentinel1 = 0xdeadbeef;
			gci->sentinel2 = reinterpret_cast<UInt32*>(reinterpret_cast<char*>(gci) + sz);
			*gci->sentinel2 = 0xdeadbeef;
#endif
			
			if(flagAsConst)
				gci->gcflags |= GCInfo::GCOF_ConstantArray;

			const void *defaultInstance = NULL;
			if(structureType)
				defaultInstance = structureType->_native.actualDefaultValue;

			if(defaultInstance)
			{
				// Construct by cloning the default instance
				for(LargeInt i=0;i<numElements;i++)
					BlockCopy(reinterpret_cast<Byte*>(&gci->_objectData) + (i*elementSize), defaultInstance, static_cast<size_t>(elementSize));

				// Zero out padded elements
				if(overflow)
					memset(reinterpret_cast<Byte*>(&gci->_objectData) + (numElements * elementSize), 0, static_cast<size_t>(overflow * elementSize));
			}
			else
				memset(reinterpret_cast<Byte*>(&gci->_objectData), 0, static_cast<size_t>(numPaddedElements * elementSize));


			gci->LinkBefore(&_linkTail, _liveSetGCL);

			CRef<void> cref(&gci->_objectData);

			return cref;
		}

		CRef<const String> RDXObjectManager::CreateStringFromCS(OperationContext *ctx, CandidateString *cs, bool lookupOnly)
		{
			CRef<const String> strRef;
			HashValue hash;
			const String *outStrPtr;

#ifdef RDX_ENABLE_SMP
			Threading::AtomicIncrement(&_stringReadAttempts);
			while(Threading::AtomicRead(&_stringWriteAttempts) != 0)
			{
				Threading::AtomicDecrement(&_stringReadAttempts);
				BeginBlockingOperation(ctx, COREMUTEX_StringTableInsert);
				Threading::AtomicIncrement(&_stringReadAttempts);
				EndBlockingOperation(ctx, COREMUTEX_StringTableInsert);
			}
#endif
			
			bool found = _stringTable.GetElement(cs, &outStrPtr, &hash);

			if(!found)
			{
				if(lookupOnly)
					return NULL;

#ifdef RDX_ENABLE_SMP
				Threading::AtomicIncrement(&_stringWriteAttempts);
				Threading::AtomicDecrement(&_stringReadAttempts);

				BeginBlockingOperation(ctx, COREMUTEX_StringTableInsert);

				// Wait for read attempts to finish or block
				while(Threading::NonAtomicRead(&_stringReadAttempts) != 0)
				{
				}
				Threading::Synchronize();

				// Might have been inserted while we were waiting, retry
				found = _stringTable.GetElement(cs, &outStrPtr, &hash);


				if(found)
					strRef = outStrPtr;
				else
#endif
				{
					RDX_TRY(ctx)
					{
						CRef<String> newString;
						RDX_PROTECT_ASSIGN(ctx, newString, CreateObject<String>(ctx, _builtins.st_String) );

						String *strp = newString;
						RDX_PROTECT(ctx, _stringTable.Insert(ctx, cs, &strp, hash));

						new (strp) String(cs->feedback, GCInfo::From(cs->feedback)->numElements);
						
						strRef = newString;
					}
					RDX_CATCH(ctx)
					{
#ifdef RDX_ENABLE_SMP
						Threading::AtomicDecrement(&_stringWriteAttempts);
						EndBlockingOperation(ctx, COREMUTEX_StringTableInsert);
#endif
						RDX_RETHROWV(ctx, NULL);
					}
					RDX_ENDTRY
				}
				
#ifdef RDX_ENABLE_SMP
				Threading::AtomicDecrement(&_stringWriteAttempts);
				EndBlockingOperation(ctx, COREMUTEX_StringTableInsert);
#endif
			}
			else
			{
				strRef = outStrPtr;
#ifdef RDX_ENABLE_SMP
				Threading::AtomicDecrement(&_stringReadAttempts);
#endif
			}
			
			return strRef;
		}

		CRef<const String> RDXObjectManager::CreateStringASCII(OperationContext *ctx, const char *str, LargeInt size, bool lookupOnly)
		{
			if(str == NULL)
				return NULL;
			if(size == -1)
				size = static_cast<LargeInt>(strlen(str));

			CandidateString cs;
			cs.format = CandidateString::CSF_ASCII;
			cs.numBytes = size;
			cs.bytes = str;
			if(!cs.CountCharacters())
				return NULL;

			return CreateStringFromCS(ctx, &cs, lookupOnly);
		}

		CRef<const String> RDXObjectManager::CreateString(OperationContext *ctx, const Char *str, LargeInt numChars, bool lookupOnly)
		{
			if(str == NULL)
				return NULL;

			if(numChars == -1)
			{
				const Char *scan = str;
				numChars = 0;

				while(*scan)
				{
					numChars++;
					scan++;
				}
			}

			CandidateString cs;
			cs.format = CandidateString::CSF_Char;
			cs.numBytes = numChars * static_cast<LargeInt>(sizeof(Char));
			cs.bytes = str;
			if(!cs.CountCharacters())
				return NULL;

			return CreateStringFromCS(ctx, &cs, lookupOnly);
		}

		CRef<const String> RDXObjectManager::CreateStringConcatenated(OperationContext *ctx, const String *str1, const String *str2)
		{
			if(str2 == NULL)
				return str1;
			if(str1 == NULL)
				return str2;

			CandidateString cs;
			cs.format = CandidateString::CSF_Concatenated;
			cs.numBytes = str1->Length() * static_cast<LargeInt>(sizeof(Char));
			cs.bytes = str1->AsChars();
			cs.numBytes2 = str2->Length() * static_cast<LargeInt>(sizeof(Char));
			cs.bytes2 = str2->AsChars();

			// Change the first one to the actual byte count
			if(!Utility::CheckAddOverflow(cs.numBytes, cs.numBytes2))
				RDX_LTHROWV(ctx, Errors::RDX_ERROR_INTEGER_OVERFLOW, NULL);

			cs.numBytes += cs.numBytes2;
			cs.numCharacters = cs.numBytes / static_cast<LargeInt>(sizeof(Char));

			return CreateStringFromCS(ctx, &cs, false);
		}

		CRef<const String> RDXObjectManager::CreateStringSub(OperationContext *ctx, const String *str, LargeInt startIndex, LargeInt length)
		{
			if(!str)
				return str;
			if(startIndex < 0)
				startIndex = 0;
			else if(startIndex >= str->Length())
				return CreateString(ctx, RDX_STATIC_STRING(""), 0);
			
			LargeInt maxLength = str->Length() - startIndex;
			if(length < 0 || length > maxLength)
				length = maxLength;

			return CreateString(ctx, str->AsChars() + startIndex, length, false);
		}

		CRef<const String> RDXObjectManager::CreateStringUTF8(OperationContext *ctx, const Byte *str, LargeInt size, bool lookupOnly)
		{
			if(str == NULL)
				return NULL;

			if(size == -1)
			{
				const Byte *scan = str;
				size = 0;

				while(*scan)
				{
					size++;
					scan++;
				}
			}

			CandidateString cs;
			cs.format = CandidateString::CSF_UTF8;
			cs.numBytes = size;
			cs.bytes = str;
			if(!cs.CountCharacters())
				return NULL;

			return CreateStringFromCS(ctx, &cs, lookupOnly);
		}

		CRef<RuntimeThread> RDXObjectManager::CreateThread(OperationContext *ctx, LargeInt stackSize)
		{
			CRef<RuntimeThread> rt;

			RDX_TRY(ctx)
			{
				RDX_PROTECT_ASSIGN(ctx, rt, CreateContainer(ctx, static_cast<LargeInt>(sizeof(RuntimeThread)),
					1, 0, DOMAIN_Runtime, _builtins.st_Thread, NULL, 0).Cast<RuntimeThread>() );

				new (rt) RuntimeThread();
				rt->stackBytes = static_cast<UInt8*>(_allocator.Realloc(NULL, stackSize, RDX_MAX_ALIGNMENT));
				if(!rt->stackBytes)
					RDX_STHROW(ctx, Errors::RDX_ERROR_ALLOCATION_FAILED);

				rt->stackCapacity = stackSize;
				rt->ownerObjectManager = this;
				rt->insertionPoint = rt->stackBytes + rt->stackCapacity;
				return rt;
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROWV(ctx, NULL);
			}
			RDX_ENDTRY
		}

		void RDXObjectManager::AddUnloadedObject(OperationContext *ctx, void *obj)
		{
			GCInfo::From(obj)->gcflags |= (GCInfo::GCOF_Shelled | GCInfo::GCOF_ReferencesMayBeShells);

			RDX_TRY(ctx)
			{
				RDX_PROTECT(ctx, _pendingDeshellObjects.Add(ctx, this, GCInfo::From(obj)));
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROW(ctx);
			}
			RDX_ENDTRY
		}

		void RDXObjectManager::AddGlobalSymbol(OperationContext *ctx, const String *symbolName, void *object)
		{
			if(symbolName == NULL)
				return;

			GCInfo::From(object)->gstSymbol = symbolName;
#ifdef RDX_ENABLE_DEBUG_GST_SYMBOL
			GCInfo::From(object)->debugGSTSymbol = symbolName->AsChars();
#endif
			_gst.Insert(ctx, &symbolName, &object);
		}

		Domain RDXObjectManager::HostGetSymbolDomain(String *symbol)
		{
			if(symbol->StartsWith("#"))
				return DOMAIN_Duplicable;

			if(symbol->StartsWith("Core."))
				return DOMAIN_Core;

			return DOMAIN_Invalid;
		}

		// Attempts to resolve any import symbols in unloaded packages.  Returns true if all imports were resolved, false otherwise.
		bool RDXObjectManager::ResolveImports(OperationContext *ctx, IPackageHost *host)
		{
			bool allResolved = true;

			RDX_TRY(ctx)
			{
				for(LargeInt oi=0;oi<_unloadedPackages.numObjects;oi++)
				{
					Package *pkg = reinterpret_cast<Package*>(&_unloadedPackages.objects[oi]->_objectData);

					// Load symbols
					LargeInt nSymbols = GCInfo::From(pkg->_native.importedSymbols)->numElements;
					for(LargeInt i=0;i<nSymbols;i++)
					{
						Package::ManifestImport *mi = pkg->_native.importedSymbols + i;

						if(!mi->ref.resolution)
						{
							void *objRef;
							bool found = _gst.GetElement(&mi->symbolName, &objRef);

							if(!found)
							{
								allResolved = false;
							}
							else
							{
								if(!host->DomainsVisible(pkg->_native.domain, mi->domain))
									RDX_STHROW(ctx, Errors::RDX_ERROR_DOMAIN_POLICY_VIOLATION);
								mi->ref.resolution = objRef;
							}
						}
					}
				}

				return allResolved;
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROWV(ctx, false);
			}
			RDX_ENDTRY
		}

		bool RDXObjectManager::TypeIsValid(const Type *t) const
		{
			if(!t) return true;
			if(GCInfo::From(t)->containerType == _builtins.st_ArrayOfType ||
				GCInfo::From(t)->containerType == _builtins.st_StructuredType ||
				GCInfo::From(t)->containerType == _builtins.st_DelegateType)
				return true;
			return false;
		}

		bool RDXObjectManager::ObjectIsConstant(const void *obj) const
		{
			if(obj == NULL)
				return false;
			if((GCInfo::From(obj)->gcflags & GCInfo::GCOF_ConstantArray) != 0)
				return true;
			return false;
		}

		bool RDXObjectManager::TypeCanBeTraced(const Type *t) const
		{
			if(t == NULL)
				return false;	// NULLs are object references, but they're not traceable

			if(TypeIsObjectReference(t))
				return true;

			if(GCInfo::From(t)->containerType == _builtins.st_StructuredType)
			{
				const StructuredType *st = static_cast<const StructuredType*>(t);
				if(st->_native.containedReferences)
					return true;
			}
			return false;
		}

		bool RDXObjectManager::TypeIsObjectReference(const Type *t) const
		{
			if(!t) return true;
			if(GCInfo::From(t)->containerType == _builtins.st_DelegateType) return true;
			if(GCInfo::From(t)->containerType == _builtins.st_ArrayOfType) return true;
			if(GCInfo::From(t)->containerType == _builtins.st_StructuredType)
			{
				const StructuredType *st = static_cast<const StructuredType*>(t);
				if(st->storageSpecifier == EnumValue::From(StructuredType::SS_Class) ||
					st->storageSpecifier == EnumValue::From(StructuredType::SS_Interface))
					return true;
			}
			return false;
		}

		bool RDXObjectManager::RefTypesCompatibleRecursive(const Type *from, const Type *to, const Type *initialFrom, int depth) const
		{
			if(depth == RDX_MAX_RECURSION_DEPTH)
				return false;

			const GCInfo *toInfo = GCInfo::From(to);

			if(from == NULL)
			{
				// NULL can be cast to reference types
				return TypeIsObjectReference(to);
			}

			if(from == to)
				return true;

			if(from == NULL || to == NULL)
				return false;	// Corrupt type def?

			if(to == _builtins.st_Object)
				return true;

			const GCInfo *fromInfo = GCInfo::From(from);

			if(fromInfo->containerType == _builtins.st_ArrayOfType)
			{
				if(to == _builtins.st_Array || to == _builtins.st_Object) return true;

				if(toInfo->containerType == _builtins.st_ArrayOfType)
				{
					const ArrayOfType *aotFrom = static_cast<const ArrayOfType*>(from);
					const ArrayOfType *aotTo = static_cast<const ArrayOfType*>(to);
					const Type *subFrom = aotFrom->type;
					const Type *subTo = aotTo->type;

					if(aotFrom->isConstant != FalseValue && aotTo->isConstant == FalseValue)
						return false;	// Conversion from constant to non-constant

					if(aotFrom->numDimensions != aotTo->numDimensions)
						return false;	// Dimension count mismatch

					if(subFrom == initialFrom)
						return false;	// Circular type def

					if(subFrom == subTo)
						return true;	// Subtypes match exactly

					// Not an exact match
					if(aotTo->isConstant == FalseValue)
						return false;	// Can't convert to a parent type unless the array is constant

					if(TypeIsObjectReference(subFrom))
						return RefTypesCompatibleRecursive(subFrom, subTo, initialFrom, depth + 1);
					else
						return NonRefTypesCompatible(subFrom, subTo);
				}

				return false;
			}

			if(fromInfo->containerType == _builtins.st_DelegateType)
			{
				if(to == _builtins.st_Method || to == _builtins.st_Object) return true;
				return false;
			}

			if(fromInfo->containerType == _builtins.st_StructuredType &&
				static_cast<const StructuredType*>(from)->storageSpecifier == EnumValue::From(StructuredType::SS_Class))
			{
				if(toInfo->containerType == _builtins.st_StructuredType)
				{
					if(static_cast<const StructuredType*>(to)->storageSpecifier == EnumValue::From(StructuredType::SS_Class))
					{
						const StructuredType *st = static_cast<const StructuredType*>(from)->parentClass;
						while(st)
						{
							if(st == initialFrom)	// Recursive (corrupt)
								return false;
							if(st == to)
								return true;
							st = st->parentClass;
						}
						return false;
					}
					else if(static_cast<const StructuredType*>(to)->storageSpecifier == EnumValue::From(StructuredType::SS_Interface))
					{
						const StructuredType *st = static_cast<const StructuredType*>(from);
						LargeInt numInterfaces = 0;
						if(st->interfaces)
							numInterfaces = GCInfo::From(st->interfaces)->numElements;
						for(LargeInt i=0;i<numInterfaces;i++)
							if(st->interfaces[i].type == to)
								return true;
						return false;
					}
				}
				return false;
			}
			return false;
		}

		
		bool RDXObjectManager::NonRefTypesCompatible(const Type *from, const Type *to) const
		{
			if(GCInfo::From(from)->containerType == _builtins.st_StructuredType
				&& static_cast<const StructuredType *>(from)->storageSpecifier == EnumValue::From(StructuredType::SS_Enum)
				&& to == _builtins.RDX_ENUM_INTERNAL_TYPE)
				return true;

			return from == to;
		}

		bool RDXObjectManager::TypesCompatible(const Type *from, const Type *to) const
		{
			if(TypeIsObjectReference(from))
				return RefTypesCompatibleRecursive(from, to, from, 0);

			if(GCInfo::From(from)->containerType == _builtins.st_StructuredType
				&& static_cast<const StructuredType *>(from)->storageSpecifier == EnumValue::From(StructuredType::SS_Enum)
				&& to == _builtins.RDX_ENUM_INTERNAL_TYPE)
				return true;

			return from == to;
		}
		
		bool RDXObjectManager::TypesCompatiblePolymorphic(const Type *from, const Type *to) const
		{
			if(TypesCompatible(to, from))
				return true;	// Target can be directly converted to source, so they're definitely convertable

			// Conversions to and from interfaces are valid if a subclass could contain it.
			// This means that interface-interface conversions are valid and interface-class conversions are valid as long as the class isn't final.
			if(GCInfo::From(from)->containerType == _builtins.st_StructuredType && GCInfo::From(to)->containerType == _builtins.st_StructuredType)
			{
				const StructuredType *fromST = static_cast<const StructuredType *>(from);
				const StructuredType *toST = static_cast<const StructuredType *>(to);

				if(fromST->storageSpecifier == EnumValue::From(StructuredType::SS_Interface))
				{
					return (toST->storageSpecifier == EnumValue::From(StructuredType::SS_Interface)) || 
						(toST->storageSpecifier == EnumValue::From(StructuredType::SS_Class) && !toST->isFinal);
				}
				if(toST->storageSpecifier == EnumValue::From(StructuredType::SS_Interface))
				{
					return (fromST->storageSpecifier == EnumValue::From(StructuredType::SS_Class) && !fromST->isFinal);
				}
			}
			return false;
		}

		void RDXObjectManager::TypeValueSize(OperationContext *ctx, const Type *t, LargeInt &size, LargeInt &align) const
		{
			if(t == NULL)
			{
				size = sizeof(void*);
				align = RDX_ALIGN_POINTER;
				return;
			}

			if(t == _builtins.st_Varying)
			{
				// This should never be called on varying
				RDX_LTHROW(ctx, Errors::RDX_ERROR_INTERNAL_BAD_TYPE);
			}
			else if(GCInfo::From(t)->containerType == _builtins.st_StructuredType)
			{
				const StructuredType *st = static_cast<const StructuredType*>(t);
				switch(st->storageSpecifier.Value())
				{
				case StructuredType::SS_Class:
				case StructuredType::SS_Interface:
					size = sizeof(void*);
					align = RDX_ALIGN_POINTER;
					break;
				case StructuredType::SS_Enum:
					size = sizeof(EnumValue);
					align = ALIGN_EnumValue;
					break;
				case StructuredType::SS_ValStruct:
				case StructuredType::SS_RefStruct:
					if((st->_native.flags & StructuredType::NativeProperties::STF_StructureEvaluated) == 0)
						size = align = -1;
					else
					{
						size = st->_native.size;
						align = st->_native.alignment;
					}
					break;
				default:
					RDX_LTHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
				};
			}
			else if(GCInfo::From(t)->containerType == _builtins.st_DelegateType ||
				GCInfo::From(t)->containerType == _builtins.st_ArrayOfType)
			{
				size = sizeof(void*);
				align = RDX_ALIGN_POINTER;
			}
			else
				RDX_LTHROW(ctx, Errors::RDX_ERROR_INTERNAL_BAD_TYPE);
		}

		bool RDXObjectManager::EnumCompatible(EnumValue ev, const Enumerant *enums) const
		{
			if(enums == NULL)
				return false;

			if(ev == EnumValue::From(0))
				return true;	// 0 is always valid

			LargeInt searchMin = 0;
			LargeInt searchSpan = GCInfo::From(enums)->numElements;

			// Binary search
			while(searchSpan > 0)
			{
				LargeInt searchMid = searchMin + (searchSpan / 2);
				EnumValue evMid = enums[searchMid].value;
				if(evMid < ev)
				{
					LargeInt newMin = searchMid + 1;
					searchSpan = searchMin + searchSpan - newMin;
					searchMin = newMin;
				}
				else if(evMid > ev)
					searchSpan = searchMid - searchMin;
				else
					return true;	// Matched, this is OK
			}
			return false;
		}

		bool RDXObjectManager::ObjectCompatible(const void *from, const Type *to) const
		{
			if(from == NULL)
				return true;
			if(to == NULL)
				return from == NULL;

			if(to == _builtins.st_Object)
				return true;	// Can cast anything to Object, including structural resources

			if(GCInfo::From(to)->containerType == _builtins.st_DelegateType)
			{
				if(GCInfo::From(from)->containerType != _builtins.st_Method)
					return false;
				const Method *m = static_cast<const Method*>(from);
				const DelegateType *dt = static_cast<const DelegateType *>(to);
				if(ResolveShellableReference(m->returnTypes) != ResolveShellableReference(dt->returnTypes))
					return false;
				if(ResolveShellableReference(m->parameters) != ResolveShellableReference(dt->parameters))
					return false;
				return true;
			}
			else
				return TypesCompatible(GCInfo::From(from)->containerType, to);
		}

		void RDXObjectManager::ResolveObjectInteriorReferences(OperationContext *ctx, void *obj, bool finalStep)
		{
			GCInfo *info = GCInfo::From(obj);

			RDX_TRY(ctx)
			{
				// FIXME: Code dupe from GraphDependencies
				if(info->containerType)
				{
					if(!info->containedStructure)
					{
						// Reference list
						void **asArray = reinterpret_cast<void**>(obj);
						for(LargeInt i=0;i<info->numElements;i++)
						{
							void *resolved = ResolveShellableReference(asArray[i]);
							if(resolved || asArray[i] == NULL)
								asArray[i] = resolved;
							else if(finalStep)
								RDX_STHROW(ctx, Errors::RDX_ERROR_UNRESOLVED_SYMBOL_REFERENCE);
						}
					}
					else
					{
						LargeInt elementSize = info->elementSize;
						LargeInt nElements = info->numElements;

						// Scan out references from the reference layout table
						const StructuredType::NativeProperties::ContainedReference *refs = info->containedStructure->_native.containedReferences;

						const GCInfo *csgci = GCInfo::From(info->containedStructure);

						if(refs)
						{
							LargeInt nRefs = 0;
							if(refs)
								nRefs = GCInfo::From(refs)->numElements;

							for(LargeInt i=0;i<nElements;i++)
							{
								UInt8 *base = reinterpret_cast<UInt8*>(obj) + elementSize*i;
								for(LargeInt j=0;j<nRefs;j++)
								{
									void **refp = reinterpret_cast<void**>(base + refs[j].offset);
									void *ref = *refp;

									if(ref)
									{
										void *resolved = ResolveShellableReference(ref);
										
										// This is generally safe because refs can not be resolved during the critical phase unless they are a critical type.
										// Because critical types are all builtins that are fully-formed in advance, there are no unknown types that could interfere
										// with the compatibility check

										if(resolved)
										{
											const GCInfo *ri = GCInfo::From(resolved);
											if(!GCInfo::From(resolved)->containerType)
												RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);	// This should never happen

											if(refs[j].mustBeConstant && (GCInfo::From(resolved)->gcflags & GCInfo::GCOF_ConstantArray) == 0)
											{
												const GCInfo *refType = GCInfo::From(GCInfo::From(resolved)->containerType);
												RDX_STHROW(ctx, Errors::RDX_ERROR_MUSTBECONST_PROPERTY_REFERENCES_NON_CONST_ARRAY);
											}

											const GCInfo *fti = GCInfo::From(GCInfo::From(resolved)->containerType);
											const GCInfo *tti = GCInfo::From(refs[j].requiredType);

											if(finalStep)
											{
												if(!ObjectCompatible(resolved, refs[j].requiredType))
													RDX_STHROW(ctx, Errors::RDX_ERROR_INCOMPATIBLE_CONVERSION);
											}
											*refp = resolved;
										}
										else
										{
											// Everything must resolve in the final step, but references to critical types must resolve
											if(finalStep || !refs[j].requiredType || RefIsShell(refs[j].requiredType) || (GCInfo::From(refs[j].requiredType)->gcflags & GCInfo::GCOF_Critical))
											{
												bool isShell = RefIsShell(refs[j].requiredType);
												UInt32 critFlag =  (GCInfo::From(refs[j].requiredType)->gcflags & GCInfo::GCOF_Critical);
												Package::ManifestLocal *ml = reinterpret_cast<Package::ManifestLocal*>(GCInfo::From(ref));
												Package::ManifestImport *mi = reinterpret_cast<Package::ManifestImport*>(GCInfo::From(ref));
												RDX_STHROW(ctx, Errors::RDX_ERROR_UNRESOLVED_SYMBOL_REFERENCE);
											}
										}
									}
									else
										*refp = NULL;
								}
							}	// for(...numElements)
						}	// if(refs || cbds)
					}	// if(info->containedStructure)
				}	// if(info->containerType)
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROW(ctx);
			}
			RDX_ENDTRY
		}


		void RDXObjectManager::ResolveInteriorReferences(OperationContext *ctx, bool finalStep)
		{
			RDX_TRY(ctx)
			{
				for(LargeInt oi=0;oi<_pendingDeshellObjects.numObjects;oi++)
				{
					GCInfo *link = _pendingDeshellObjects.objects[oi];
					if(link == NULL)
						continue;

					void *obj = &link->_objectData;

					RDX_PROTECT(ctx, ResolveObjectInteriorReferences(ctx, obj, finalStep) );

					if(finalStep)
						link->gcflags &= ~GCInfo::GCOF_ReferencesMayBeShells;
				}
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROW(ctx);
			}
			RDX_ENDTRY
		}

		bool RDXObjectManager::ResolveStructureDefault(OperationContext *ctx, StructuredType *st)
		{
			// This can be called before references are de-shelled, will have to de-shell them on the fly
			RDX_TRY(ctx)
			{
				if(!(st->_native.flags & StructuredType::NativeProperties::STF_DependencyDefaultsEvaluated) &&
					(st->_native.flags & StructuredType::NativeProperties::STF_StructureEvaluated))
				{
					RDX_PROTECT(ctx, ResolveObjectInteriorReferences(ctx, st, false));
					
					// Create a basic default
					if(st->_native.actualDefaultValue == NULL)
					{
						RDX_PROTECT_ASSIGN(ctx, st->_native.actualDefaultValue,
							CreateContainer(ctx, st->_native.size, 1, 0, GCInfo::From(st)->domain, st, NULL, 0) );
					}
					void *defaultInstance = st->_native.actualDefaultValue;

					LargeInt firstProperty = 0;
					LargeInt numProperties = 0;

					const Property *properties = st->properties;
					if(properties)
					{
						if(RefIsShell(properties))
							return false;	// Properties aren't loaded, defer

						numProperties = GCInfo::From(properties)->numElements;
					}

					StructuredType *parentClass = st->parentClass;
					if(parentClass)
					{
						if(RefIsShell(parentClass))
							return false;	// Parent class isn't loaded, defer

						if(!(st->parentClass->_native.flags & StructuredType::NativeProperties::STF_DefaultEvaluated))
							return false;	// Parent wasn't evaluated, defer

						// Verify that the initial properties are all of the same type
						const Property *parentProperties = st->parentClass->properties;
						LargeInt numParentProperties = 0;
						if(parentProperties)
						{
							// This should never happen, if the parent has STF_DefaultEvaluated set then the parent properties should not be a shell
							if(RefIsShell(parentProperties))
								RDX_STHROW(ctx, Errors::RDX_ERROR_UNRESOLVED_SYMBOL_REFERENCE);
							numParentProperties = GCInfo::From(parentProperties)->numElements;
						}

						if(numParentProperties > numProperties)
							RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

						RDX_VERBOSE( printf("Size of property: %i\n", sizeof(Property)) );

						const GCInfo *poi = GCInfo::From(properties);
						const GCInfo *ppoi = GCInfo::From(parentProperties);

						for(LargeInt i=0;i<numParentProperties;i++)
						{
							if(properties[i].type != parentProperties[i].type)
								RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
						}
					}

					for(LargeInt i=0;i<numProperties;i++)
					{
						const Property *p = properties + i;
						if(GCInfo::From(p->type)->containerType == _builtins.st_StructuredType)
						{
							const StructuredType *pst = static_cast<const StructuredType *>(p->type);
							if(!pst)
								RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
							if(RefIsShell(pst))
								RDX_STHROW(ctx, Errors::RDX_ERROR_UNRESOLVED_SYMBOL_REFERENCE);

							if(pst->storageSpecifier == EnumValue::From(StructuredType::SS_ValStruct) ||
								pst->storageSpecifier == EnumValue::From(StructuredType::SS_RefStruct))
							{
								LargeInt pOffset = st->_native.propertyOffsets[i];
								void *propertyLocation = reinterpret_cast<char*>(defaultInstance) + pOffset;

								// Copy the struct
								if(!(pst->_native.flags & StructuredType::NativeProperties::STF_DefaultEvaluated))
									return false;	// Dependency not loaded
								if(pst->_native.actualDefaultValue != NULL)
									BlockCopy(propertyLocation, pst->_native.actualDefaultValue, static_cast<size_t>(pst->_native.size));
							}
						}
					}

					// Overwrite the default properties with the old instance
					if(st->parentClass && (st->parentClass->_native.actualDefaultValue))
						BlockCopy(defaultInstance, st->parentClass->_native.actualDefaultValue, static_cast<size_t>(st->parentClass->_native.size));

					st->_native.flags |= StructuredType::NativeProperties::STF_DependencyDefaultsEvaluated;
					if(st->defaultValue == NULL)
					{
						// If nothing overrides, keep this
						st->_native.flags |= StructuredType::NativeProperties::STF_DefaultEvaluated;
						// If the parent class has the same size and nothing is overriding, then recycle its default
						if(st->parentClass && st->_native.size == st->parentClass->_native.size)
							st->_native.actualDefaultValue = st->parentClass->_native.actualDefaultValue;
					}

					return true;	// Made some progress
				}

				if(RefIsShell(st->defaultValue))
				{
					void *dv = ResolveShellableReference(st->defaultValue);
					if(!dv)
						return false;	// Not loaded yet

					const GCInfo *defaultGCI = GCInfo::From(dv);
					if(defaultGCI->domain == DOMAIN_Duplicable || defaultGCI->domain != GCInfo::From(st)->domain)
					{
						const GCInfo *stGCI = GCInfo::From(st);
						RDX_STHROW(ctx, Errors::RDX_ERROR_DOMAIN_POLICY_VIOLATION);
					}

					if(GCInfo::From(dv)->containerType != st)
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

					// Clone the default value
					const GCInfo *dvinfo = GCInfo::From(dv);
					CRef<void> clonedDV;
					RDX_PROTECT_ASSIGN(ctx, clonedDV, CreateContainer(ctx, dvinfo->elementSize, dvinfo->numElements, dvinfo->numDimensions, dvinfo->domain, dvinfo->containerType, dvinfo->typeProcessor, 0));
					BlockCopy(clonedDV, dv, static_cast<LargeUInt>(dvinfo->elementSize * dvinfo->numElements));

					st->_native.actualDefaultValue = clonedDV;
					st->_native.flags |= StructuredType::NativeProperties::STF_DefaultEvaluated;
					return true;
				}

				return false;
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROWV(ctx, false);
			}
			RDX_ENDTRY
		}

		void RDXObjectManager::VerifyDuplicates(OperationContext *ctx, IPackageHost *packageHost)
		{
			IO::IFileStream *stream = NULL;
			bool isText = false;

			RDX_TRY(ctx)
			{
				for(LargeInt oi=0;oi<_unloadedPackages.numObjects;oi++)
				{
					Package *pkg = reinterpret_cast<Package*>(&_unloadedPackages.objects[oi]->_objectData);

					// Load symbols
					LargeInt nSymbols = GCInfo::From(pkg->_native.localSymbols)->numElements;
					for(LargeInt i=0;i<nSymbols;i++)
					{
						Package::ManifestLocal *ml = pkg->_native.localSymbols + i;

						if(ml->flags & Package::ManifestLocal::PMLF_Duplicate)
						{
							if(!stream)
								stream = packageHost->StreamForDomain(this, pkg->_native.domain, false, isText);

							// This is of the appropriate criticality, load it
							bool loadedOK;
							CRef<void> oldRef = ml->ref.resolution;

							RDX_PROTECT_ASSIGN( ctx, loadedOK, DeserializeObject(ctx, this, pkg, ml, pkg->_native.domain, packageHost, stream, isText) );

							GCInfo::From(ml->ref.resolution)->gcflags |= GCInfo::GCOF_TransientDuplicate;

							CRef<void> duplicateObj = ml->ref.resolution;
							ml->ref.resolution = oldRef;

							if(!loadedOK)
								RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

							RDX_PROTECT(ctx, ResolveObjectInteriorReferences(ctx, duplicateObj, true) );

							void *gstObj;
							bool foundElement = _gst.GetElement(&ml->symbolName, &gstObj);

							if(!foundElement)
								RDX_STHROW(ctx, Errors::RDX_ERROR_INTERNAL_DUPLICATE_LOST_GST);

							if(GCInfo::From(gstObj)->containerType != GCInfo::From(duplicateObj)->containerType)
								RDX_STHROW(ctx, Errors::RDX_ERROR_DUPLICATED_SYMBOL_MISMATCH);

							LargeInt numElements = GCInfo::From(gstObj)->numElements;
							if(numElements != GCInfo::From(duplicateObj)->numElements)
								RDX_STHROW(ctx, Errors::RDX_ERROR_DUPLICATED_SYMBOL_MISMATCH);

							LargeInt elementSize = sizeof(void*);
							if(GCInfo::From(gstObj)->containedStructure)
								elementSize = GCInfo::From(gstObj)->containedStructure->_native.size;

							int memcmpResult;

							if(GCInfo::From(gstObj)->containedStructure &&
								(GCInfo::From(gstObj)->containedStructure->_native.user.flags & StructuredType::NativeProperties::UserProperties::STUF_NativeChangesDuringLoad))
							{
								LargeInt nativeSize = GCInfo::From(gstObj)->containedStructure->_native.user.nativeSize;
								memcmpResult = memcmp(reinterpret_cast<UInt8*>(gstObj) + nativeSize, reinterpret_cast<UInt8*>(static_cast<void*>(duplicateObj)) + nativeSize, static_cast<size_t>(elementSize - nativeSize));
							}
							else
								memcmpResult = memcmp(gstObj, duplicateObj, static_cast<size_t>(elementSize * numElements));
						}
					}

					if(stream)
						stream->Close();
					stream = NULL;
				}
			}
			RDX_CATCH(ctx)
			{
				if(stream)
					stream->Close();
				RDX_RETHROW(ctx);
			}
			RDX_ENDTRY
		}

		// Changes to internal structures can cause this function to fail very easily, usually with (defer && !loadedAny) failing
		// 
		void RDXObjectManager::LoadSymbolsOfCriticality(OperationContext *ctx, IPackageHost *packageHost, bool criticality)
		{
			IO::IFileStream *stream = NULL;
			bool isText = false;

			RDX_TRY(ctx)
			{
				bool defer = true;
				bool gstInserts = false;
				while(defer)
				{
					bool loadedAny = false;
					defer = false;

					if(gstInserts)
						RDX_PROTECT(ctx, ResolveImports(ctx, packageHost));
					gstInserts = false;

					for(LargeInt oi=0;oi<_unloadedPackages.numObjects;oi++)
					{
						Package *pkg = reinterpret_cast<Package*>(&_unloadedPackages.objects[oi]->_objectData);

						GCInfo *isi = GCInfo::From(pkg->_native.importedSymbols);

						// Load symbols
						LargeInt nSymbols = GCInfo::From(pkg->_native.localSymbols)->numElements;
						for(LargeInt i=0;i<nSymbols;i++)
						{
							Package::ManifestLocal *ml = pkg->_native.localSymbols + i;

							// Resolving types is a first-run operation, ALL type references need to be resolved or failures can result later
							if(!ml->resolvedType)
							{
								if(!ml->typeRef)
									RDX_STHROW(ctx, Errors::RDX_ERROR_INTERNAL_GENERAL);

								UInt32 debugCritFlag = GCInfo::From(_builtins.aot_Property)->gcflags;

								void *unresolved = ml->typeRef->InterpretAs<void>();
								void *resolved = ResolveShellableReference(unresolved);

								if(resolved)
								{
									Type *t = static_cast<Type*>(resolved);
									if(!TypeIsValid(t))
										RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
									ml->resolvedType = t;

									if(GCInfo::From(t)->gcflags & GCInfo::GCOF_Critical)
										ml->flags |= Package::ManifestLocal::PMLF_Critical;

									loadedAny = true;
								}
								else
								{
									defer = true;
								}
							}

							if(ml->ref.resolution == NULL)
							{
								void *objRef;
								if(ml->symbolName && _gst.GetElement(&ml->symbolName, &objRef))
								{
									if(ml->domain != DOMAIN_Duplicable && !(GCInfo::From(objRef)->gcflags & GCInfo::GCOF_Duplicable))
										RDX_STHROW(ctx, Errors::RDX_ERROR_NON_DUPLICABLE_SYMBOL_COLLISION);

									ml->flags |= Package::ManifestLocal::PMLF_Duplicate;
									ml->ref.resolution = objRef;
									loadedAny = true;
								}
								else
								{
									if( ml->resolvedType &&
										((ml->flags & Package::ManifestLocal::PMLF_Critical) != 0) == criticality)
									{
										if(criticality == false
											&& ml->typeRef->resolution == _builtins.st_Method
											&& !packageHost->DomainCanContainMethods(pkg->_native.domain))
										{
											const GCInfo *methodGCI = GCInfo::From(ml->ref.resolution);
											RDX_STHROW(ctx, Errors::RDX_ERROR_DOMAIN_POLICY_VIOLATION);
										}

										if(!stream)
											stream = packageHost->StreamForDomain(this, pkg->_native.domain, false, isText);

										// This is of the appropriate criticality, load it
										bool loadedOK;
										RDX_PROTECT_ASSIGN( ctx, loadedOK, DeserializeObject(ctx, this, pkg, ml, pkg->_native.domain, packageHost, stream, isText) );

										if(loadedOK)
										{
											loadedAny = true;

											// Assign it to the GST if it's the first instance
											if(ml->symbolName && !(ml->flags & Package::ManifestLocal::PMLF_Anonymous))
											{
												gstInserts = true;
												RDX_PROTECT( ctx, AddGlobalSymbol(ctx, ml->symbolName, ml->ref.resolution) );
											}
										}
										else
										{
											defer = true;
										}
									}
								}
							}
							else
							{
								// Is actually loaded

								if(GCInfo::From(ml->ref.resolution)->containerType == _builtins.st_StructuredType &&
									!(static_cast<StructuredType*>(ml->ref.resolution)->_native.flags & StructuredType::NativeProperties::STF_DefaultEvaluated) )
								{
									// This has to wait until after structure hardening
									if(!criticality)
									{
										bool loadedOK;
										defer = true;
										RDX_PROTECT_ASSIGN(ctx, loadedOK, ResolveStructureDefault(ctx, static_cast<StructuredType*>(ml->ref.resolution)) );
										if(loadedOK)
											loadedAny = true;
									}
								}
							}
						}

						if(stream)
							stream->Close();
						stream = NULL;
					}

					if(defer && !loadedAny)
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);	// Unresolvable dependency
				}
			}
			RDX_CATCH(ctx)
			{
				if(stream)
					stream->Close();
				RDX_RETHROW(ctx);
			}
			RDX_ENDTRY
		}

		CRef<Package> RDXObjectManager::LoadSinglePackage(OperationContext *ctx, Domain domain, IPackageHost *packageHost)
		{
			CRef<Package> pkg = NULL;
			IO::IFileStream *stream = NULL;

			RDX_TRY(ctx)
			{
				bool isText = false;

				Package *pkgRef;
				if(_packages.GetElement(&domain, &pkgRef))
					return pkgRef;

				isText = false;
				stream = packageHost->StreamForDomain(this, domain, false, isText);

				if(!stream)
					RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

				RDX_PROTECT_ASSIGN(ctx, pkg, DeserializePackage(ctx, this, domain, packageHost, stream, isText) );

				stream->Close();
				stream = NULL;

				RDX_PROTECT(ctx, RegisterPackage(ctx, domain, pkg) );

				Package::NativeProperties *pkgNative = &pkg->_native;

				GCInfo::From(pkg)->gcflags |= GCInfo::GCOF_UnloadedPackage;
				RDX_PROTECT(ctx, _unloadedPackages.Add(ctx, this, GCInfo::From(pkg)));

				// Determine imports
				LargeInt nImports = GCInfo::From(pkg->_native.importedSymbols)->numElements;
				for(LargeInt i=0;i<nImports;i++)
				{
					Package::ManifestImport *import = pkg->_native.importedSymbols + i;
					Domain symDomain = packageHost->DomainForSymbolName(this, import->symbolName);
					import->domain = symDomain;
				}
				return pkg;
			}
			RDX_CATCH(ctx)
			{
				if(stream)
					stream->Close();
				RDX_RETHROWV(ctx, NULL);
			}
			RDX_ENDTRY
		}

		CRef<void> RDXObjectManager::LoadObject(OperationContext *ctx, IPackageHost *packageHost)
		{
			BeginBlockingOperation(ctx, COREMUTEX_SymbolTableAccess);

			RDX_TRY(ctx)
			{
				CRef<Package> pkg;
				RDX_PROTECT_ASSIGN(ctx, pkg, LoadPackage(ctx, DOMAIN_Runtime, packageHost) );

				// Throw out this package
				if(pkg != NULL)
				{
					Domain domain = DOMAIN_Runtime;
					bool found;
					_packages.RemoveEntry(_packages.FindElementIndex(&domain, found, NULL));
					_packages.Balance();
				}

				if(pkg == NULL || pkg->_native.localSymbols == NULL || GCInfo::From(pkg->_native.localSymbols)->numElements == 0)
					RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

				EndBlockingOperation(ctx, COREMUTEX_SymbolTableAccess);
				CRef<void> obj = pkg->_native.firstObject;
				pkg->_native.firstObject = NULL;
				return obj;
			}
			RDX_CATCH(ctx)
			{
				CollectGarbage(ctx);
				EndBlockingOperation(ctx, COREMUTEX_SymbolTableAccess);
				RDX_RETHROWV(ctx, NULL);
			}
			RDX_ENDTRY
		}

		void RDXObjectManager::HardenStructures(OperationContext *ctx)
		{
			RDX_TRY(ctx)
			{
				bool resolvedAny = false;
				bool firstPass = true;
				bool deferredAny = true;

				while(deferredAny)
				{
					resolvedAny = false;
					deferredAny = false;

					for(LargeInt oi=0;oi<_pendingDeshellObjects.numObjects;oi++)
					{
						GCInfo *link = _pendingDeshellObjects.objects[oi];
						if(link == NULL)
							continue;

						if(link->containerType == _builtins.st_StructuredType)
						{
							StructuredType *st = reinterpret_cast<StructuredType*>(&link->_objectData);

							if(!(st->_native.flags & StructuredType::NativeProperties::STF_StructureEvaluated) )
							{
								bool resolved;
								RDX_PROTECT_ASSIGN(ctx, resolved, ResolveStructure(ctx, st ) );
								if(resolved)
								{
									resolvedAny = true;
								}
								else
								{
									deferredAny = true;
								}
							}
						}
						else if(link->containerType == _builtins.st_ArrayOfType)
						{
							if(firstPass)
							{
								ArrayOfType *t = reinterpret_cast<ArrayOfType*>(&link->_objectData);
								if(t->type == _builtins.st_Varying)
									RDX_STHROW(ctx, Errors::RDX_ERROR_FORBIDDEN_VARYING_USAGE);
								if(t->type == NULL)
									RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
								if(RefIsShell(t->type))
									RDX_STHROW(ctx, Errors::RDX_ERROR_UNRESOLVED_SYMBOL_REFERENCE);
							}
						}
					}

					if(!resolvedAny && deferredAny)
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);

					firstPass = false;
				}
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROW(ctx);
			}
			RDX_ENDTRY
		}

		void RDXObjectManager::ValidateStructures(OperationContext* ctx)
		{
			// Perform runtime safety validation on structures
			// NOTE: This is performed AFTER data loading, so checks that determine whether a type is safe
			// to load must occur at a different stage, such as ResolveStructure
			RDX_TRY(ctx)
			{
				for(LargeInt oi=0;oi<_pendingDeshellObjects.numObjects;oi++)
				{
					GCInfo *link = _pendingDeshellObjects.objects[oi];
					if(link == NULL)
						continue;

					if(link->containerType == _builtins.st_StructuredType)
						RDX_PROTECT(ctx, ValidateStructure(ctx, reinterpret_cast<StructuredType*>(&link->_objectData)));
				}
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROW(ctx);
			}
			RDX_ENDTRY
		}

		void RDXObjectManager::FinishPackageLoad(OperationContext* ctx)
		{
			RDX_TRY(ctx)
			{
				RDX_PROTECT(ctx, _codeProvider->InitializeSymbolDictionary(ctx, this) );

				// Move all objects pending deshell to pending process
				for(LargeInt oi=0;oi<_pendingDeshellObjects.numObjects;oi++)
				{
					GCInfo *link = _pendingDeshellObjects.objects[oi];
					link->gcflags &= ~GCInfo::GCOF_Shelled;
					link->gcflags |= GCInfo::GCOF_Unprocessed;
				}

				// Copy the entire list
				_pendingProcessObjects = _pendingDeshellObjects;

				// Evict the old list
				_pendingDeshellObjects.EvictAll();

				bool defer = true;
				while(defer)
				{
					bool loadedAny = false;
					defer = false;

					for(LargeInt oi=0;oi<_pendingProcessObjects.numObjects;oi++)
					{
						GCInfo *link = _pendingProcessObjects.objects[oi];
						if(link == NULL)
							continue;

						bool deferThis = false;

						const Type *containerType = link->containerType;
						if(containerType && GCInfo::From(containerType)->containerType == _builtins.st_StructuredType)
						{
							const StructuredType *st = static_cast<const StructuredType*>(containerType);
							if(st->_native.user.typeProcessor)
							{
								bool loadedOK;
								RDX_PROTECT_ASSIGN(ctx, loadedOK, st->_native.user.typeProcessor->OnLoad(ctx, &link->_objectData, this) );
								if(!loadedOK)
									deferThis = true;
								else
									loadedAny = true;
							}
						}

						if(!deferThis)
						{
							link->gcflags &= ~GCInfo::GCOF_Unprocessed;
							_pendingProcessObjects.objects[oi] = NULL;
						}
						else
							defer = true;
					}

					if(defer && !loadedAny)
						RDX_STHROW(ctx, Errors::RDX_ERROR_PACKAGE_CORRUPTED);
				}

				_pendingProcessObjects.EvictAll();

				// Wipe all non-anchored references from packages
				for(LargeInt oi=0;oi<_unloadedPackages.numObjects;oi++)
				{
					Package *pkg = reinterpret_cast<Package *>(&_unloadedPackages.objects[oi]->_objectData);
					if(pkg->_native.localSymbols)
					{
						LargeInt numLocalSymbols = GCInfo::From(pkg->_native.localSymbols)->numElements;
						if(numLocalSymbols > 0 && pkg->_native.domain == DOMAIN_Runtime)
							pkg->_native.firstObject = pkg->_native.localSymbols[0].ref.resolution;
						for(LargeInt si=0;si<numLocalSymbols;si++)
						{
							Package::ManifestLocal *mfl = pkg->_native.localSymbols + si;
							if((mfl->flags & Package::ManifestLocal::PMLF_Anonymous) || mfl->symbolName == NULL)
							{
								mfl->ref.resolution = NULL;
								mfl->resolvedType = NULL;
								mfl->symbolName = NULL;
								mfl->tempTypeName = NULL;
								mfl->typeRef = NULL;
							}
						}
					}
					
					if(pkg->_native.importedSymbols)
					{
						LargeInt numImportedSymbols = GCInfo::From(pkg->_native.importedSymbols)->numElements;
						for(LargeInt si=0;si<numImportedSymbols;si++)
						{
							Package::ManifestImport *imp = pkg->_native.importedSymbols + si;
							imp->ref.resolution = NULL;
							imp->symbolName = NULL;
						}
					}
					GCInfo::From(pkg)->gcflags &= ~GCInfo::GCOF_UnloadedPackage;
				}
				_unloadedPackages.EvictAll();
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROW(ctx);
			}
			RDX_ENDTRY
		}

		void RDXObjectManager::FinishDeserialize(OperationContext *ctx, IPackageHost *packageHost)
		{
			RDX_TRY(ctx)
			{
				RDX_PROTECT(ctx, ResolveImports(ctx, packageHost) );
				RDX_PROTECT(ctx, LoadSymbolsOfCriticality(ctx, packageHost, true) );
				RDX_PROTECT(ctx, ResolveInteriorReferences(ctx, false) );

				RDX_PROTECT(ctx, HardenStructures(ctx) );

				RDX_PROTECT(ctx, LoadSymbolsOfCriticality(ctx, packageHost, false) );

				bool resolved;
				RDX_PROTECT_ASSIGN(ctx, resolved, ResolveImports(ctx, packageHost) );
				if(!resolved)
					RDX_STHROW(ctx, Errors::RDX_ERROR_UNRESOLVED_SYMBOL_REFERENCE);

				RDX_PROTECT(ctx, ResolveInteriorReferences(ctx, true) );
				RDX_PROTECT(ctx, VerifyDuplicates(ctx, packageHost) );

				RDX_PROTECT(ctx, ValidateStructures(ctx));

				RDX_PROTECT(ctx, FinishPackageLoad(ctx) );
			}
			RDX_CATCH(ctx)
			{
				RDX_RETHROW(ctx);
			}
			RDX_ENDTRY
		}

		CRef<Package> RDXObjectManager::LoadPackage(OperationContext *ctx, Domain domain, IPackageHost *packageHost)
		{
			// This function is not reentrant.  It will fully load one package and dependencies.  Individual packages are loaded via LoadSinglePackages.
			CRef<Package> pkg = NULL;

			RDX_TRY(ctx)
			{
				_forcePackagesRelevant = true;	// Make sure we don't collect unloaded packages

				RDX_PROTECT_ASSIGN(ctx, pkg, LoadSinglePackage(ctx, domain, packageHost) );

				for(LargeInt oi=0;oi<_unloadedPackages.numObjects;oi++)
				{
					GCInfo *pkgLink = _unloadedPackages.objects[oi];
					if(pkgLink == NULL)
						continue;

					Package *subPkg = reinterpret_cast<Package *>(&pkgLink->_objectData);
					if(subPkg->_native.importedSymbols)
					{
						LargeInt nImports = GCInfo::From(subPkg->_native.importedSymbols)->numElements;
						for(LargeInt i=0;i<nImports;i++)
						{
							Package::ManifestImport *import = subPkg->_native.importedSymbols + i;
							RDX_PROTECT(ctx, LoadSinglePackage(ctx, import->domain, packageHost) );
						}
					}
				}
				
				RDX_PROTECT(ctx, FinishDeserialize(ctx, packageHost) );

				_forcePackagesRelevant = false;
			}
			RDX_CATCH(ctx)
			{
				_forcePackagesRelevant = false;

				// Evict processing lists for collection
				_unloadedPackages.EvictAll();
				_pendingDeshellObjects.EvictAll();
				_pendingProcessObjects.EvictAll();

				RDX_RETHROWV(ctx, NULL);
			}
			RDX_ENDTRY

			return pkg;
		}

		void WriteUTF8String(const String *str, IO::IFileStream *fs)
		{
			const Char *chars = str->AsChars();
			LargeInt nChars = str->Length();

			{
				// Determine UTF8 length;
				LargeInt utf8len = 0;
				for(LargeInt i=0;i<nChars;i++)
				{
					UInt8 encoded[10];
					utf8len += EncodeUTF8Char(chars[i], encoded);
				}

				fs->WriteConverted<LargeInt, BinPackageLargeInt>(utf8len);
			}

			const LargeInt backlogSize = 50;
			const LargeInt backlogLimit = 45;
			UInt8 backlog[backlogSize];
			LargeInt backlogOffset = 0;

			// Determine UTF8 length

			for(LargeInt i=0;i<nChars;i++)
			{
				backlogOffset += EncodeUTF8Char(chars[i], backlog + backlogOffset);
				if(backlogOffset >= backlogLimit)
				{
					fs->WriteBytes(backlog, backlogOffset);
					backlogOffset = 0;
				}
			}

			if(backlogOffset)
				fs->WriteBytes(backlog, backlogOffset);
		}


		
		void RDXObjectManager::SavePackageFile(OperationContext *ctx, Domain domain, IO::IFileStream *fs,
			const void *object, SaveMode saveMode, bool isText)
		{
			FileWriteSerializer fws(domain, this);

			ISerializer *ser = &fws;
			StartSerialize(&fws, _scanSetGCL);

			switch(saveMode)
			{
			case SAVEMODE_Package:
				{
					const Package *pkg = static_cast<const Package*>(object);
				
					Package::ManifestLocal *symbols = pkg->_native.localSymbols;
					LargeInt nSymbols = GCInfo::From(symbols)->numElements;
					for(LargeInt i=0;i<nSymbols;i++)
					{
						Package::ManifestLocal *ml = symbols + i;

						SerializeIncludeObject(&fws, ml->ref.resolution, _scanSetGCL);
					}
				}
				break;
			case SAVEMODE_SingleObject:
				{
					SerializeIncludeObject(&fws, object, _scanSetGCL);
				}
				break;
			};

			FinishSerialize(&fws, _scanSetGCL, false);

			// Include all GST symbols so that we have an accurate object count for the SSID table
			{
				GCInfo *scanObj = _linkHead.next[_scanSetGCL];
				while(scanObj != &_linkTail)
				{
					if(scanObj->gcflags & GCInfo::GCOF_External && scanObj->gstSymbol)
						SerializeIncludeObject(&fws, scanObj->gstSymbol, _scanSetGCL);
					scanObj = scanObj->next[_scanSetGCL];
				}
			}

			LargeInt numIncludedObjects = _scanObjectCounter[_scanSetGCL];
			SSIDTable::Entry *objectSymbolIDs = _allocator.CAlloc<SSIDTable::Entry>(numIncludedObjects);
			if(!objectSymbolIDs)
			{
				fs->Abort();
				return;
			}

			// Count all object types and populate the SSID table
			LargeInt numImports = 0;
			LargeInt numLocalSymbols = 0;
			LargeInt numStrings = 0;
			{
				LargeInt ssidIndex = 0;
				GCInfo *scanObj = _linkHead.next[_scanSetGCL];
				while(scanObj != &_linkTail)
				{
					LargeInt ssid;
					if(scanObj->gcflags & GCInfo::GCOF_External)
						ssid = -(numImports++) - 1;
					else
					{
						if(scanObj->containerType == _builtins.st_String)
							ssid = (numStrings++) + 1;
						else
							ssid = (numLocalSymbols++) + 1;
					}

					objectSymbolIDs[ssidIndex].key = StaticLookupPODKey<const GCInfo *>(scanObj);
					objectSymbolIDs[ssidIndex].value = ssid;
					ssidIndex++;

					scanObj = scanObj->next[_scanSetGCL];
				}
			}

			// Create the SSID table
			SSIDTable ssidTable(objectSymbolIDs, numIncludedObjects);

			WriteHeader(this, fs, isText, numLocalSymbols, numImports, numStrings);

			// Write string table, update string symbol IDs to be after the local table
			LargeInt stringTableLocation = fs->Tell();
			if(!isText)
			{
				GCInfo *scanObj = _linkHead.next[_scanSetGCL];
				while(scanObj != &_linkTail)
				{
					if(!(scanObj->gcflags & GCInfo::GCOF_External))
					{
						if(scanObj->containerType == _builtins.st_String)
						{
							WriteUTF8String(reinterpret_cast<const String*>(&scanObj->_objectData), fs);
							StaticLookupPODKey<const GCInfo *> objKey(scanObj);
							(*ssidTable.Lookup(objKey)) += numLocalSymbols;
						}
					}
					scanObj = scanObj->next[_scanSetGCL];
				}
			}

			RDX_VERBOSE( printf("String table written to %i\n", fs->Tell()) );


			// Write catalogs
			{
				GCInfo *scanObj = _linkHead.next[_scanSetGCL];
				while(scanObj != &_linkTail)
				{
					if(scanObj->gcflags & GCInfo::GCOF_External)
						WriteImport(ctx, this, fs, isText, &ssidTable, scanObj->gstSymbol);
					scanObj = scanObj->next[_scanSetGCL];
				}
			}

			RDX_VERBOSE( printf("Import catalog written to %i\n", fs->Tell()) );

			LargeInt exportCatalogStartLocation = fs->Tell();
			{
				GCInfo *scanObj = _linkHead.next[_scanSetGCL];
				while(scanObj != &_linkTail)
				{
					if(!(scanObj->gcflags & GCInfo::GCOF_External))
					{
						if(scanObj->containerType != _builtins.st_String)
							ReserveObjectExport(this, fs, isText, &ssidTable, &scanObj->_objectData);
					}
					scanObj = scanObj->next[_scanSetGCL];
				}
			}
				
			// Write objects
			{
				LargeInt catalogLocation = exportCatalogStartLocation;
				LargeInt objectLocation = fs->Tell();
				GCInfo *scanObj = _linkHead.next[_scanSetGCL];
				while(scanObj != &_linkTail)
				{
					if(!(scanObj->gcflags & GCInfo::GCOF_External))
					{
						if(scanObj->containerType != _builtins.st_String)
						{
							LargeInt objectStartLocation = fs->Tell();
							WriteObject(this, fs, isText, &ssidTable, &scanObj->_objectData);
							ObjectManagement::WriteObjectExport(this, fs, isText, &catalogLocation, objectStartLocation, &scanObj->_objectData);
						}
					}
					scanObj = scanObj->next[_scanSetGCL];
				}
			}

			// Unlink everything
			{
				LargeInt objectIndex = 0;
				GCInfo *scanObj = _linkHead.next[_scanSetGCL];
				while(scanObj != &_linkTail)
				{
					GCInfo *next = scanObj->next[_scanSetGCL];
					scanObj->Unlink(_scanSetGCL);
					scanObj = next;
				}
			}

			_allocator.Free(objectSymbolIDs);
		}

		void RDXObjectManager::SaveObject(OperationContext *ctx, const void *object, IO::IFileStream *fs, bool isText)
		{
			if(GCInfo::From(object)->domain != DOMAIN_Runtime)
				RDX_LTHROW(ctx, Errors::RDX_ERROR_SAVED_PACKAGED_OBJECT);

			BeginBlockingOperation(ctx, COREMUTEX_GlobalOperation);

			RDX_TRY(ctx)
			{
				RDX_PROTECT(ctx, SavePackageFile(ctx, DOMAIN_Runtime, fs, object, SAVEMODE_SingleObject, isText) );
			}
			RDX_CATCH(ctx)
			{
				EndBlockingOperation(ctx, COREMUTEX_GlobalOperation);
				RDX_RETHROW(ctx);
			}
			RDX_ENDTRY

			EndBlockingOperation(ctx, COREMUTEX_GlobalOperation);
		}

		void RDXObjectManager::SavePackage(OperationContext *ctx, Domain domain, IPackageHost *packageHost)
		{
			BeginBlockingOperation(ctx, COREMUTEX_GlobalOperation);

			Package *pkg;
			if(!_packages.GetElement(&domain, &pkg))
			{
				EndBlockingOperation(ctx, COREMUTEX_GlobalOperation);
				return;
			}

			bool isText;
			IO::IFileStream *fs = packageHost->StreamForDomain(this, domain, true, isText);

			if(fs)
			{
				SavePackageFile(ctx, domain, fs, pkg, SAVEMODE_Package, isText);
				fs->Close();
			}

			EndBlockingOperation(ctx, COREMUTEX_GlobalOperation);
		}

		void RDXObjectManager::RegisterPackage(OperationContext *ctx, Domain domain, Package *pkg)
		{
			_packages.Insert(ctx, &domain, &pkg);
		}

		bool RDXObjectManager::PackageLoaded(Domain domain)
		{
			return _packages.ContainsKey(&domain);
		}

		CRef<ArrayOfType> RDXObjectManager::CreateArrayType(OperationContext *ctx, Type *t, LargeInt numDimensions, bool constant)
		{
			BeginBlockingOperation(ctx, COREMUTEX_SymbolTableAccess);

			RDX_TRY(ctx)
			{
				CRef<Char> characters;
				LargeInt gstSymbolLength;
				LargeInt arrayNameLength;

				{
					CRef<const String> gstSymbol = GCInfo::From(t)->gstSymbol;

					if(!GCInfo::From(t)->gstSymbol)
						return NULL;	// Can't create an array type with no GST binding

					gstSymbolLength = gstSymbol->Length();
					RDX_PROTECT_ASSIGN(ctx, characters, Create1DArray<Char>(ctx, gstSymbolLength + 3 + numDimensions) );
					BlockCopy(characters + 1, gstSymbol->AsChars(), gstSymbolLength * sizeof(Char));
					characters[0] = static_cast<Char>('#');

					Char *dimOut = characters + gstSymbolLength + 1;
					dimOut[0] = static_cast<Char>('[');
					LargeInt cOffset = 0;
					if(constant)
					{
						dimOut[1] = 'C';
						cOffset++;
					}
					for(LargeInt i=1;i<numDimensions;i++)
						dimOut[i+cOffset] = static_cast<Char>(',');
					dimOut[numDimensions+cOffset] = static_cast<Char>(']');
					arrayNameLength = gstSymbolLength + 2 + numDimensions + cOffset;
				}

				CRef<const String> desiredSymbol;
				RDX_PROTECT_ASSIGN(ctx, desiredSymbol, CreateString(ctx, characters, arrayNameLength) );

				CRef<void> obj;
				obj = LookupSymbolSimple(ctx, desiredSymbol);

				if(obj)
				{
					if(GCInfo::From(obj)->containerType != _builtins.st_ArrayOfType)
						RDX_STHROW(ctx, Errors::RDX_ERROR_INCOMPATIBLE_CONVERSION);

					const ArrayOfType *aot = obj.Cast<ArrayOfType>();
					if(aot->numDimensions != numDimensions ||
						(aot->isConstant != FalseValue) != constant ||
						aot->type != t)
						RDX_STHROW(ctx, Errors::RDX_ERROR_INTERNAL_BAD_TYPE);	// Incompatible definition of the array type exists
					return obj.Cast<ArrayOfType>();
				}

				CRef<ArrayOfType> aot;
				RDX_PROTECT_ASSIGN(ctx, aot, CreateContainer(ctx, sizeof(ArrayOfType), 1, 0, DOMAIN_Duplicable, _builtins.st_ArrayOfType, NULL, 0).Cast<ArrayOfType>() );
				aot->numDimensions = numDimensions;
				aot->type = t;
				aot->isConstant = (constant ? TrueValue : FalseValue);

				RDX_PROTECT(ctx, AddGlobalSymbol(ctx, desiredSymbol, aot) );

				EndBlockingOperation(ctx, COREMUTEX_SymbolTableAccess);

				return aot;
			}
			RDX_CATCH(ctx)
			{
				EndBlockingOperation(ctx, COREMUTEX_SymbolTableAccess);
				RDX_RETHROWV(ctx, NULL);
			}
			RDX_ENDTRY
		}

		void RDXObjectManager::DebugDumpGST()
		{
			if(_gst._native.untracedEntries == NULL)
				return;
			LargeInt nElements = _gst._native.numEntries;
			wprintf(L"GST entry table: %p\n", _gst._native.untracedEntries);
			for(int i=0;i<nElements;i++)
			{
				if(_gst._native.untracedEntries[i].e.elementType > HashElement::HMT_ContainsData)
				{
					wprintf(L"GST %i: %p = %s\n", i, _gst._native.untracedEntries[i].k, _gst._native.untracedEntries[i].k->AsChars());
				}
			}
		}

		CRef<void> RDXObjectManager::LookupSymbolSimple(OperationContext *ctx, const String *symbolName)
		{
			if(symbolName == NULL)
				return NULL;

			BeginBlockingOperation(ctx, COREMUTEX_SymbolTableAccess);

			void *rv = NULL;
			if(_gst.GetElement(&symbolName, &rv))
			{
				EndBlockingOperation(ctx, COREMUTEX_SymbolTableAccess);
				return this->ResolveShellableReference(rv);
			}
			EndBlockingOperation(ctx, COREMUTEX_SymbolTableAccess);
			return rv;
		}

		CRef<void> RDXObjectManager::LookupSymbol(OperationContext *ctx, const String *symbolName, IPackageHost *packageHost)
		{
			BeginBlockingOperation(ctx, COREMUTEX_SymbolTableAccess);

			CRef<void> rv;
			rv = this->LookupSymbolSimple(ctx, symbolName);
			if(rv)
			{
				EndBlockingOperation(ctx, COREMUTEX_SymbolTableAccess);
				return rv;
			}

			Domain domain = packageHost->DomainForSymbolName(this, symbolName);

			if(domain == DOMAIN_Invalid)
			{
				EndBlockingOperation(ctx, COREMUTEX_SymbolTableAccess);
				return NULL;	// Bad symbol
			}

			RDX_TRY(ctx)
			{
				CRef<Package> pkg;
				RDX_PROTECT_ASSIGN(ctx, pkg, this->LoadPackage(ctx, domain, packageHost) );
				rv = this->LookupSymbolSimple(ctx, symbolName);

				EndBlockingOperation(ctx, COREMUTEX_SymbolTableAccess);
				return rv;
			}
			RDX_CATCH(ctx)
			{
				CollectGarbage(ctx);
				EndBlockingOperation(ctx, COREMUTEX_SymbolTableAccess);
				RDX_RETHROWV(ctx, NULL);
			}
			RDX_ENDTRY
		}

		// Statics
		RDXObjectManager::MethodProcessor			RDXObjectManager::MethodProcessor::instance;
		RDXObjectManager::StringProcessor			RDXObjectManager::StringProcessor::instance;
		RDXObjectManager::StructuredTypeProcessor	RDXObjectManager::StructuredTypeProcessor::instance;

		RDXObjectManager::StringSerializer			RDXObjectManager::StringSerializer::instance;
		RDXObjectManager::BoolSerializer			RDXObjectManager::BoolSerializer::instance;

		IObjectManager *CreateObjectManager(Allocator alloc, const INativeTypeHost *nth, const ICodeProvider *cp)
		{
			RDXObjectManager *om = NULL;
			{
				OperationContext ctx(NULL);

				om = alloc.CAlloc<RDXObjectManager>(1);
				if(!om)
					return NULL;

				new (om) RDXObjectManager(alloc, nth, cp);

				RDX_TRY(&ctx)
				{
					RDX_PROTECT(&ctx, om->InitializeCoreMutexes(&ctx) );
				}
				RDX_CATCH(&ctx)
				{
					if(om)
						alloc.Free(om);
					return NULL;
				}
				RDX_ENDTRY
			}

			// Mutexes are set up, get a real context and perform remaining init operations
			{
				OperationContext ctx(om);

				RDX_NTRY(EH2, &ctx)
				{
					RDX_NPROTECT(EH2, &ctx, om->InitializeBuiltInTypes(&ctx) );
					om->CollectGarbage(&ctx);
				}
				RDX_NCATCH(EH2, &ctx)
				{
					om->CollectGarbage(&ctx);
					if(om)
						alloc.Free(om);
					return NULL;
				}
				RDX_NENDTRY(EH2)

			}

			return om;
		}
	};

	namespace Programmability
	{

		void Method::DetermineIntrinsicState()
		{
			if(this == NULL)
				return;

			const String *str = GCInfo::From(this)->gstSymbol;
			if(!str)
				return;

			if(_native.intrinsicStateChecked)
				return;

			_native.intrinsicStateChecked = true;
			const Intrinsics::NativeFunction *nf = Intrinsics::LookupIntrinsicFunction(str);

			if(nf)
			{
				_native.isIntrinsic = true;
				_native.falseCheckOpcode = nf->falseCheckOpcode;
				_native.isBranching = nf->isBranching;
				_native.neverFails = nf->neverFails;
				_native.opcode = nf->opcode;
				_native.p2 = nf->p2;
				_native.p3 = nf->p3;
			}
		}
	}
};
